<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>DockYard blog</title>
  <id>https://dockyard.com/blog</id>
  <link href="https://dockyard.com/blog"/>
  <link href="https://dockyard.com/blog/atom.xml" rel="self"/>
  <updated>2016-10-20T00:00:00Z</updated>
  <author><name>DockYard</name></author>
  <entry>
    <title>Building a Shared Language</title>
    <link rel="alternate" href="https://dockyard.com/blog/2017/05/30/building-a-shared-language" />
    <id>https://dockyard.com/blog/2017/05/30/building-a-shared-language</id>
    
    <published>2017-05-30 00:00:00</published>
    <updated>2017-05-31 14:55:58</updated>
    <author><name>Tim Walsh</name></author>
    <summary>A process to help understand clients and the industry youâre designing for</summary>
    <content type="html">&lt;p&gt;When we start a project at &lt;a href=&quot;http://dockyard.com&quot;&gt;DockYard&lt;/a&gt;, we rely on a process that we refer to as âDiscovery.â This exploratory period occurs at the start of an engagement and helps to uncover the parameters of a project. We treat discovery as an opportunity to identify stakeholders, business goals, project requirements, user types, communication expectations, etc.&lt;/p&gt;

&lt;p&gt;During a discovery we select techniques to help distill out problems. These problems then inform decisions for building a product. Over time this process has gotten more efficient but I wouldn&amp;#39;t say it&amp;#39;s gotten easier. Strictly because every project drums up a different set of problems, each unique to the design and the industry we&amp;#39;re designing for.&lt;/p&gt;

&lt;p&gt;Recently, our design team read &lt;a href=&quot;https://abookapart.com/products/practical-design-discovery&quot;&gt;&lt;em&gt;Practical Design Discovery&lt;/em&gt;&lt;/a&gt;, a great resource, chock-full of strategies and techniques for running a valuable discovery. One section that I found interesting talked about &amp;quot;building a shared language.&amp;quot;&lt;/p&gt;

&lt;p&gt;A crucial component of discovery is understanding - understanding the people, the users, &amp;amp; the problems. For this, we rely on language. However, as with any new project comes a glossary of new terms often referenced while explaining a project&amp;#39;s goals. If it&amp;#39;s an unfamiliar industry, this can be confounding, almost like being in a country that is foreign to you.&lt;/p&gt;

&lt;p&gt;The most recent discovery I was a part of was for a project in an industry very foreign to me.&lt;/p&gt;

&lt;p&gt;Before discovery had started, we prepared by reading a few materials including project goals, user descriptions, and desired functionality. It was quickly apparent to me that there was quite a few terms that I was unfamiliar with. I immediately thought of &amp;quot;building a shared language.&amp;quot;&lt;/p&gt;

&lt;p&gt;To help us get acquainted with the industry, I scoured the documents pulling out each unfamiliar term. I then dropped those terms into a document with space to the right of each item. During discovery we printed out the document handing it over to the stakeholders of the project. We asked them to independently define each term and its association to the project at hand, an activity that took maybe 20-30 minutes.&lt;/p&gt;

&lt;p&gt;The results were insightful. These definitions helped outline expectations for delivery. It shed light on alignment between stakeholders. It showed us that these terms could mean something different for each person, or that a discussion needs to happen to help bring people onto the same page. Not only was this revealing, it will also serve as reference material when we move deeper into the project. We can feel confident about decisions around functionality, because together we have agreed on the meaning.&lt;/p&gt;

&lt;p&gt;Discovery is really about understanding and it always helps to be able to speak the same language.  &lt;/p&gt;

&lt;p&gt;Think your company can benefit from a design discovery or other UX support? &lt;a href=&quot;https://dockyard.com/contact/hire-us&quot;&gt;Contact us.&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Experience Economy, user interviews, and design discovery</title>
    <link rel="alternate" href="https://dockyard.com/blog/2017/05/26/experience-economy-user-interviews-and-design-discovery" />
    <id>https://dockyard.com/blog/2017/05/26/experience-economy-user-interviews-and-design-discovery</id>
    
    <published>2017-05-26 00:00:00</published>
    <updated>2017-05-26 18:21:06</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>The principle of customer sacrifice illustrates how a discovery process can reveal new opportunities.</summary>
    <content type="html">&lt;p&gt;In my reading and podcast-listening lately, Iâve found myself more and more interested in business rules and principles. Part of the reason Iâm doing all this reading is, Iâm just curious about how things work. But I also noticed that the better I understand how a business operates, the more I can use design strategically to solve the right problems &lt;em&gt;at the right time&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;The principle of customer sacrifice&lt;/h2&gt;

&lt;p&gt;In &lt;em&gt;The Experience Economy&lt;/em&gt;, B. Joseph Pine II and James H. Gilmore  talk about the principle of &lt;a href=&quot;https://books.google.com/books?hl=en&amp;amp;lr=&amp;amp;id=edtOyzyKgXUC&amp;amp;oi=fnd&amp;amp;pg=PR7&amp;amp;dq=the+experience+economy&amp;amp;ots=2lsBAIOqsQ&amp;amp;sig=2d_tgqGxXrZ9TjgH3pF6Kc5hx-w#v=onepage&amp;amp;q=customer%20sacrifice&amp;amp;f=false&quot;&gt;Customer Sacrifice&lt;/a&gt;. This sacrifice happens when a customer settles for something they know is available, rather than what theyâd truly want, if only they could have it. The book explains that even a business attentive to its customers will often miss the customer sacrifice. We often measure how well a business is doing for its customers by conducting customer surveys. These questionnaires are great at measuring satisfaction levels: the difference between what a customer expected, and what they think theyâve received. &lt;/p&gt;

&lt;h3&gt;Are you limiting the upside of customer UX?&lt;/h3&gt;

&lt;p&gt;But customer satisfaction is only a good retroactive measurement: how did we do, compared to how well our customers thought we might do? Satisfaction pre-supposes that the best a business could possibly do is within the bounds of what the customer already expected. This approach is limiting because it caps potential improvements at what the customers already knew they wanted. And, perhaps more importantly, satisfaction does not measure what the customer might have preferred but assumed they couldnât have. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Experience Economy&lt;/em&gt; uses &lt;a href=&quot;https://books.google.com/books?hl=en&amp;amp;lr=&amp;amp;id=edtOyzyKgXUC&amp;amp;oi=fnd&amp;amp;pg=PR7&amp;amp;dq=the+experience+economy&amp;amp;ots=2lsBAIOqsQ&amp;amp;sig=2d_tgqGxXrZ9TjgH3pF6Kc5hx-w#v=onepage&amp;amp;q=pepsi&amp;amp;f=false&quot;&gt;soft drink preference&lt;/a&gt; to illustrate this second type of missed opportunity. On most airlines, if asked for a Pepsi, the attendant will offer a Coke instead. After a few flights, the customer would realize Pepsi is not an option and start asking for a Coke instead. If the airline were to measure customer satisfaction at this point, it would look like the customer received exactly what they wanted, and thereâs no room for improvement. The airline would miss an existing opportunity to improve customer experience by providing a preferred drink.&lt;/p&gt;

&lt;h2&gt;Understand customer sacrifice through user interviews during design discovery&lt;/h2&gt;

&lt;p&gt;Customer sacrifice is one of the reasons unbiased, open-ended user interviews are so important. We normally conduct several of these as part of a &lt;a href=&quot;https://dockyard.com/services/design&quot;&gt;design discovery&lt;/a&gt;. When you apply design thinking, and &lt;a href=&quot;https://dockyard.com/blog/2015/03/11/ask-good-questions&quot;&gt;ask good questions&lt;/a&gt; youâll get a broad set of insights from users. The interview style I always recommend, and practice myself, includes open-ended questions and touches on the experience around the product, not just the product itself. Doing this work takes time, but the quality and depth of insight is well worth the investment.&lt;/p&gt;

&lt;p&gt;My favorite, most rewarding moments when leading a design project are when discovery wraps up, and I can confidently propose a way forward based on what weâve learned. It usually goes something like this: hereâs the problem you hired us to solve. But actually, your customers are experiencing a slightly different problem. And hereâs how you can be even more successful in the future by solving &lt;em&gt;that&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As a designer, itâs a humbling experience to be able to jump into a business problem, rapidly learn its key aspects from the folks who are infinitely more experienced in their field than I am, then talk to their users and other stakeholdersâ¦ and come back with something new or surprising. How can we do this? Part of what helps us find these new things is a &lt;a href=&quot;https://dockyard.com/blog/2015/03/23/beginner-mentality&quot;&gt;beginnerâs mentality&lt;/a&gt;. (I call it: &lt;em&gt;weâre not afraid to ask the âstupidâ questions!&lt;/em&gt;) Another part is - applying the right process to a business problem at the right time will yield results. Design can still have a limited interpretation as âdecorative stuffâ, but more and more businesses are &lt;a href=&quot;https://designintechreport.wordpress.com&quot;&gt;realizing designâs strategic role in tech&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Reading more business books, in a funny way, makes me more optimistic for the future of design. Iâm making connections and realizing that the business world has terms for the stuff Iâve sometimes been doing intuitively, because it feels right and gives results. &lt;/p&gt;

&lt;p&gt;If your company could benefit from a strategic design engagement, &lt;a href=&quot;https://dockyard.com/contact/hire-us&quot;&gt;contact us&lt;/a&gt;. &lt;/p&gt;
</content>
  </entry><entry>
    <title>Optimizing Your Elixir and Phoenix projects with ETS</title>
    <link rel="alternate" href="https://dockyard.com/blog/2017/05/19/optimizing-elixir-and-phoenix-with-ets" />
    <id>https://dockyard.com/blog/2017/05/19/optimizing-elixir-and-phoenix-with-ets</id>
    
    <published>2017-05-19 00:00:00</published>
    <updated>2017-05-22 15:03:04</updated>
    <author><name>Chris McCord</name></author>
    <summary>Learn how to optimize your elixir applications with a fast in-memory store</summary>
    <content type="html">&lt;p&gt;Many Elixir programmers have probably heard references to &amp;quot;ets&amp;quot; or
&amp;quot;ETS&amp;quot; in talks, or may have seen calls to the Erlang &lt;code&gt;:ets&lt;/code&gt; module in
code, but I would wager the majority haven&amp;#39;t used this feature of
Erlang in practice. Let&amp;#39;s change that.&lt;/p&gt;

&lt;p&gt;ETS, or Erlang Term Storage, is one of those innovative Erlang
features that feels like it has been hiding in plain sight once you
use it. Projects across the community like &lt;code&gt;Phoenix.PubSub&lt;/code&gt;,
&lt;code&gt;Phoenix.Presence&lt;/code&gt;, and Elixir&amp;#39;s own &lt;code&gt;Registry&lt;/code&gt; take advantage of ETS, along with many internal Erlang and Elixir modules.
Simply put, ETS is an in-memory store for Elixir and Erlang terms with
fast access. Critically, it allows access to state outside of a
process and message passing. Before we talk when to ETS (&lt;em&gt;and when not to&lt;/em&gt;), let&amp;#39;s begin with a basic primer by firing up iex:&lt;/p&gt;

&lt;p&gt;First, we&amp;#39;ll create an ETS table with &lt;code&gt;:ets.new/2&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; tab = :ets.new(:my_table, [:set])
8211
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That was easy enough. We created a table of type &lt;code&gt;:set&lt;/code&gt;, which will allows us to map unique keys to values as a standard key-value storage. Let&amp;#39;s insert a couple items:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; :ets.insert(tab, {:key1, &amp;quot;value1&amp;quot;})
true
iex&amp;gt; :ets.insert(tab, {:key2, &amp;quot;value1&amp;quot;})
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now with a couple items in place, let&amp;#39;s do a lookup:
&lt;code&gt;elixir
iex&amp;gt; :ets.lookup(tab, :key1)
[key1: &amp;quot;value1&amp;quot;]
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Notices how we aren&amp;#39;t re-binding &lt;code&gt;tab&lt;/code&gt; to a new value after inserting items. ETS tables are managed by the VM and their existence lives and dies by the process that created them. We can see this in action by killing the current iex shell process:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; Process.exit(self(), :kill)
** (EXIT from #PID&amp;lt;0.88.0&amp;gt;) killed

Interactive Elixir (1.4.4) - press Ctrl+C to exit (type h() ENTER for help)
iex&amp;gt; :ets.insert(8211, {:key1, &amp;quot;value1&amp;quot;})
** (ArgumentError) argument error
    (stdlib) :ets.insert(12307, {:key1, &amp;quot;value1&amp;quot;})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Once iex crashes, we lose our previous bindings, but we can pass the ets table ID returned from our call to &lt;code&gt;:ets.new/2&lt;/code&gt;. We can see that when we tried to access the table after its owner crashed, an &lt;code&gt;ArgumentError&lt;/code&gt; was thrown. This automatic cleanup of tables and data when the owning process crashes is one of ETS&amp;#39;s great features. We don&amp;#39;t have to be concerned about memory leaks when processes terminate after creating tables and inserting data. Here, we also got our first glimpse of the esoteric &lt;code&gt;:ets&lt;/code&gt; API and its often unhelpful errors, such as &lt;code&gt;ArgumentError&lt;/code&gt; with no other guidelines on what the problem may be. As you use the &lt;code&gt;:ets&lt;/code&gt; module more and more, you&amp;#39;ll undoubtably become famliar with frustrating argument errors and the &lt;a href=&quot;http://erlang.org/doc/man/ets.html&quot;&gt;&lt;code&gt;:ets&lt;/code&gt; documentation&lt;/a&gt; is likely to end up in your bookmarks.&lt;/p&gt;

&lt;p&gt;This just barely scratched the surface of what features ETS provides. We&amp;#39;ll only be using a fraction of its capabilities, but just remember where it really shines is fast reads and writes to key-value storage, with the ability to efficiently match on most erlang terms stored within the table (excluding maps). In our examples, we&amp;#39;ll only be storing simple key-values with basic lookups, but you should consult the docs to explore the breadth of provided features.&lt;/p&gt;

&lt;h2&gt;Optimizing &lt;code&gt;GenServer&lt;/code&gt; access with an ETS table&lt;/h2&gt;

&lt;p&gt;Optimizing code is a rewarding experince, but doubly so when you don&amp;#39;t have to change your public interface. Let&amp;#39;s see a common way ETS is used to optimize data access for state wrapped in a &lt;code&gt;GenServer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Imagine we&amp;#39;re writing a rate limiter &lt;code&gt;GenServer&lt;/code&gt; which is a process in our app that counts user requests and allows us to deny access once a user exceeds their allotted requests per minute. We know right away that we&amp;#39;ll need to store the request count state for our users somewhere, as well as a process that periodically sweeps the state once per minute. A naive first-pass with a plain-old &lt;code&gt;GenServer&lt;/code&gt; might look something like this:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule RateLimiter do
  use GenServer
  require Logger

  @max_per_minute 5
  @sweep_after :timer.seconds(60)

  ## Client

  def start_link do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  def log(uid) do
    GenServer.call(__MODULE__, {:log, uid})
  end

  ## Server
  def init(_) do
    schedule_sweep()
    {:ok, %{requests: %{}}}
  end

  def handle_info(:sweep, state) do
    Logger.debug(&amp;quot;Sweeping requests&amp;quot;)
    schedule_sweep()
    {:noreply, %{state | requests: %{}}}
  end

  def handle_call({:log, uid}, _from, state) do
    case state.requests[uid] do
      count when is_nil(count) or count &amp;lt; @max_per_minute -&amp;gt;
        {:reply, :ok, put_in(state, [:requests, uid], (count || 0) + 1)}
      count when count &amp;gt;= @max_per_minute -&amp;gt;
        {:reply, {:error, :rate_limited}, state}
    end
  end

  defp schedule_sweep do
    Process.send_after(self(), :sweep, @sweep_after)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;First, we defined &lt;code&gt;start_link/0&lt;/code&gt; which starts a &lt;code&gt;GenServer&lt;/code&gt;, using our &lt;code&gt;RateLimiter&lt;/code&gt; module as the callback module. We also named the server as our module so we can reference it later in our call to &lt;code&gt;log/1&lt;/code&gt;. Next, we defined a &lt;code&gt;log/1&lt;/code&gt; function which makes a synchronous call to the rate limiter server, asking it to log our user&amp;#39;s request. We expect to receive either &lt;code&gt;:ok&lt;/code&gt; back, to indicate our request can proceed, or &lt;code&gt;{:error, :rate_limited}&lt;/code&gt;, to indicate the user has exceeded their allotted requests, and the request should not proceed.&lt;/p&gt;

&lt;p&gt;Next, in &lt;code&gt;init/1&lt;/code&gt;, we called a &lt;code&gt;schedule_sweep/0&lt;/code&gt; function which simply has the server send itself a message one per minute to clear out all request data. Then we defined a &lt;code&gt;handle_info/2&lt;/code&gt; clause to pickup the &lt;code&gt;:sweep&lt;/code&gt; event and clear out the request state. To complete our implementation, we defined a &lt;code&gt;handle_call/3&lt;/code&gt; clause to track request state for the user and return an &lt;code&gt;:ok&lt;/code&gt;, or &lt;code&gt;{:error, :rate_limited}&lt;/code&gt; response for our caller in &lt;code&gt;log/2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s try it out in iex:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; RateLimiter.start_link()
{:ok, #PID&amp;lt;0.126.0&amp;gt;}
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
{:error, :rate_limited}

13:55:44.803 [debug] Sweeping requests
iex(9)&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It works! Once our &amp;quot;user1&amp;quot; exceeded 5 requests/minute, the server returned the expected error response. Then after we waited we observed the debug output of the state sweep, and we confirmed we were no longer rate limited. Looks great right? Unfortunately, there&amp;#39;s some serious performance issues in our implementation. Let&amp;#39;s see why.&lt;/p&gt;

&lt;p&gt;Since this feature is for rate limiting, &lt;em&gt;all user requests&lt;/em&gt; must pass through this server. Since messages are processed in serial, this effectively limits our application to single-threaded performance, and creates a bottleneck on this single process.&lt;/p&gt;

&lt;h2&gt;ETS to the rescue&lt;/h2&gt;

&lt;p&gt;Fortunately for us, Erlangers solved these kinds of problems for us. We can refactor our rate limiter server to use a publicly accessible ETS table so clients can log their requests directly in ets, and our owning process can be responsible only for sweeping and cleaning up the table. This allows concurrent reads and writes against ETS without having to serialize calls through the single server. Let&amp;#39;s make it happen:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule RateLimiter do
  use GenServer
  require Logger

  @max_per_minute 5
  @sweep_after :timer.seconds(60)
  @tab :rate_limiter_requests

  ## Client

  def start_link do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  def log(uid) do
    case :ets.update_counter(@tab, uid, {2, 1}, {uid, 0}) do
      count when count &amp;gt; @max_per_minute -&amp;gt; {:error, :rate_limited}
      _count -&amp;gt; :ok
    end
  end

  ## Server
  def init(_) do
    :ets.new(@tab, [:set, :named_table, :public, read_concurrency: true,
                                                 write_concurrency: true])
    schedule_sweep()
    {:ok, %{}}
  end

  def handle_info(:sweep, state) do
    Logger.debug(&amp;quot;Sweeping requests&amp;quot;)
    :ets.delete_all_objects(@tab)
    schedule_sweep()
    {:noreply, state}
  end

  defp schedule_sweep do
    Process.send_after(self(), :sweep, @sweep_after)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;First, we modified our &lt;code&gt;init/1&lt;/code&gt; function to create an ETS table with the &lt;code&gt;:named_table&lt;/code&gt; and &lt;code&gt;:public&lt;/code&gt; options so that callers outside of our process can access it. We also used the &lt;code&gt;read_concurrency&lt;/code&gt; and &lt;code&gt;write_concurrency&lt;/code&gt; options to optimize access. Next, we changed our &lt;code&gt;log/1&lt;/code&gt; function to write the request count to &lt;code&gt;:ets&lt;/code&gt; directly, rather than going through the &lt;code&gt;GenServer&lt;/code&gt;. This allows requests to concurrently track their own rate-limit usage. Here we used the &lt;code&gt;update_counter/4&lt;/code&gt; feature of ETS, which allows us to efficiently, and atomically, update a counter. After checking rate limit usage, we return the same value to the caller as before. Lastly, in our &lt;code&gt;:sweep&lt;/code&gt; callback, we simply use &lt;code&gt;:ets.delete_all_objects/1&lt;/code&gt; to wipe the table for the next rate limit interval.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s try it out:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; RateLimiter.start_link
{:ok, #PID&amp;lt;0.124.0&amp;gt;}
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
{:error, :rate_limited}
iex&amp;gt; :ets.tab2list(:rate_limiter_requests)
[{&amp;quot;user1&amp;quot;, 7}]
iex&amp;gt; RateLimiter.log(&amp;quot;user2&amp;quot;)
:ok
iex&amp;gt; :ets.tab2list(:rate_limiter_requests)
[{&amp;quot;user2&amp;quot;, 1}, {&amp;quot;user1&amp;quot;, 7}]

14:27:19.082 [debug] Sweeping requests

iex&amp;gt; :ets.tab2list(:rate_limiter_requests)
[]
iex&amp;gt; RateLimiter.log(&amp;quot;user1&amp;quot;)
:ok
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It works just as before. We also used &lt;code&gt;:ets.tab2list/1&lt;/code&gt; to spy on the data in the table. We can see our users requests are tracked properly, and the table is swept as expected.&lt;/p&gt;

&lt;p&gt;That&amp;#39;s all there to it. Our public interface remained unchanged and we vastly improve the performance of our mission-critical feature. Not bad!&lt;/p&gt;

&lt;h2&gt;Here Be Dragons&lt;/h2&gt;

&lt;p&gt;This just scratched the surface on what&amp;#39;s possible with ETS. But before you get too carried away and extract out all your serialized state access from &lt;code&gt;GenServer&lt;/code&gt;&amp;#39;s and &lt;code&gt;Agent&lt;/code&gt;&amp;#39;s to ETS, you need to think carefully about which actions in your application are atomic, and which require serialized access. You can easily introduce race conditions by allowing concurrent reads and writes in the pursuit of performance. One of the beautiful things about Elixir&amp;#39;s process model is the serial processing of messages. It lets us avoid race conditions exactly because we can serialize access to state that requires atomic operations. In the case of our rate limiter, each user wrote to ets with the atomic &lt;code&gt;update_counter&lt;/code&gt; operation so concurrent writes are not a problem. Use the following rules to determine if you can move from serial access to ETS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The operations must be atomic. If clients are reading data from ets in one operation, then writing to ETS based on the result, you have a race condition and the fix is serial access in a server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the operations are not atomic, ensure different processes write to distinct keys. For example, Elixir&amp;#39;s registry uses the Pid as key and allows only the current process to change its own entry. This guarantees there are no races as each process work on a different row of the ETS table&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If none of the above apply, consider keeping the operation serial. Concurrent reads with serial writes is a common ETS pattern&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you&amp;#39;re curious about using ETS for a dependency-free in-memory cache, check out SaÅ¡a JuriÄ&amp;#39;s excellent &lt;a href=&quot;https://github.com/sasa1977/con_cache&quot;&gt;ConCache&lt;/a&gt; library.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Five Business Problems Progressive Web Apps Solve</title>
    <link rel="alternate" href="https://dockyard.com/blog/2017/05/03/five-business-problems-pwas-solve" />
    <id>https://dockyard.com/blog/2017/05/03/five-business-problems-pwas-solve</id>
    
    <published>2017-05-03 00:00:00</published>
    <updated>2017-05-04 15:27:11</updated>
    <author><name>Jessica Krywosa</name></author>
    <summary>Progressive Web Apps are not only a forward thinking technology but also an answer to issues that businesses face on a daily basis.</summary>
    <content type="html">&lt;p&gt;Todayâs businesses are extremely reliant on the web. Finding and acquiring new customers while engaging and retaining current ones is a costly balancing act requiring more and more bandwidth and budget. &lt;/p&gt;

&lt;p&gt;How can businesses communicate with all customers, across all devices, and in the most cost effective way? Progressive Web Apps (PWAs) are not only forward thinking technology but also an answer to issues like this that businesses face on a daily basis. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The need to develop and maintain for multiple platforms.&lt;/strong&gt; A Progressive Web App works in the browser so there is no need for specialized development. Specifically, Chrome, Opera, and Firefox support PWAs with Safariâwhile not (yet?) supporting themâ&lt;a href=&quot;https://developers.google.com/web/showcase/2016/aliexpress&quot;&gt;still sees an increase in engagement.&lt;/a&gt; When implementing a PWA, many companies like Alibaba see a 76% &lt;a href=&quot;https://developers.google.com/web/showcase/2016/alibaba&quot;&gt;increase in conversion across all browsers&lt;/a&gt;, not only those in which they are completely supported. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile applications are not discoverable.&lt;/strong&gt; A big barrier to mobile application adoption is that they do not show up in search results. This means that new customers looking for solutions you provide are unable to find you, unless they are already aware of you. By implementing a Progressive Web App the opportunities for new user acquisition are amplified by their ability to find you on their own terms when they need you. Not to mention the fact that &lt;a href=&quot;https://webmasters.googleblog.com/2016/03/continuing-to-make-web-more-mobile.html&quot;&gt;Google rewards mobile-friendly content in itâs search algorithm&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Re-engagement and timely communication is costly (and âpeople donât read emailâ).&lt;/strong&gt; PWAs allow websites to be added to home screens on mobile devices and receive push notifications. After users opt in they can be provided timely information on sales, abandoned carts, or other information valuable to them at that specific time or location. Push notifications offer users the right information at the right time without the need to check, open, and interact with email. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Still, one experience doesnât fit both desktop and mobile visitor goals.&lt;/strong&gt; Should you want to provide a varied experience for your mobile audience this is also supported by Progressive Web Apps. Where your desktop users may be completing tasks focused on research and narrowing solutions, your mobile users may be looking to make decisions and purchases. Providing upfront information on sales, new products, or upcoming events can be spotlighted making it easier for them to move from discovery to purchase. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile sites can be slow and not user friendly.&lt;/strong&gt; It is true that mobile apps provide a user and device driven experience which many websites are not optimized for. Progressive web apps solve for this by providing an app like feeling to the user without the need to develop for multiple devices. PWAs create a faster, lighter, and interactive way for consumers to interact with a business in a way that makes sense for them. Given that &lt;a href=&quot;https://developers.google.com/web/progressive-web-apps/&quot;&gt;53% of users will abandon a site if it takes longer than 3 seconds to load&lt;/a&gt;, speed is a very important consideration. &lt;/p&gt;

&lt;p&gt;Whether combatting a poor mobile experience or trying to reduce long term costs, all businesses can benefit from upgrading to a Progressive Web App. The reduction in overhead and simplification of communication with your key customers are just a couple of ways companies can see the immediate impact of PWA implementation. &lt;/p&gt;
</content>
  </entry><entry>
    <title>DockYard Senior Engineer To Present at GOTO Chicago</title>
    <link rel="alternate" href="https://dockyard.com/blog/2017/04/28/dockyard-to-present-at-goto-conf" />
    <id>https://dockyard.com/blog/2017/04/28/dockyard-to-present-at-goto-conf</id>
    <category term="press-release" label="Press-release"/>
    <published>2017-04-28 00:00:00</published>
    <updated>2017-04-28 20:50:26</updated>
    <author><name>Jessica Krywosa</name></author>
    <summary>DockYard Senior Engineer Marten Schilstra will present at GOTO Chicago 2017.</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://dockyard.com&quot;&gt;DockYard.com&lt;/a&gt; Senior Engineer Marten Schilstra will present at &lt;a href=&quot;https://gotochgo.com&quot;&gt;GOTO Chicago&lt;/a&gt; on May 2, 2017. He joins a number of other industry experts and leaders presenting at the two day international software conference.&lt;/p&gt;

&lt;p&gt;Tuesday, May 2, Schilstra will present in the Frontend track âMaking the web frameworks titans feel tiny.â This talk will focus on Service Worker technology and solutions that web frameworks are implementing to alleviate their deficiencies.&lt;/p&gt;

&lt;p&gt;GOTO is the enterprise software development conference designed for team leads, architects, and project management organized by developers, for developers. &lt;/p&gt;

&lt;p&gt;DockYard is a software consultancy driven by creating exceptional user experiences. By approaching software with the user experience at the forefront, DockYard delivers web applications that beat out native applications in any web browser using HTML5, CSS, and JavaScript.&lt;/p&gt;
</content>
  </entry><entry>
    <title>DockYard Launches Redesigned Website</title>
    <link rel="alternate" href="https://dockyard.com/blog/2017/04/18/dockyard-launches-redesigned-website" />
    <id>https://dockyard.com/blog/2017/04/18/dockyard-launches-redesigned-website</id>
    <category term="press-release" label="Press-release"/>
    <published>2017-04-18 00:00:00</published>
    <updated>2017-04-26 09:53:50</updated>
    <author><name>Jessica Krywosa</name></author>
    <summary>Today, DockYard released a new version of their flagship website DockYard.com.</summary>
    <content type="html">&lt;p&gt;Today, DockYard released a new version of their flagship website &lt;a href=&quot;https://dockyard.com&quot;&gt;DockYard.com&lt;/a&gt;. This latest iteration provides more indepth information on DockYardâs software design and engineering services, body of work, and pursuit of best practice web app development.&lt;/p&gt;

&lt;p&gt;âOur new website design represents a collaborative effort between our design and engineering teams to deliver a clean, fast, and beautiful vision for how we want the world to view DockYard,â says Brian Cardarella, DockYard CEO. âAs with all of our internal design and engineering efforts we pushed ourselves to not compromise on the implementation.â&lt;/p&gt;

&lt;p&gt;In the coming weeks users will see even more advances on DockYard.com, including better representations on the company&amp;#39;s culture, hiring, and team. Their blogââ&lt;a href=&quot;https://dockyard.com/blog&quot;&gt;Reefpoints&lt;/a&gt;ââwill also receive a refresh with a design that better organizes content and provides a more immersive reading experience. New case studies and exclusive content on Progressive Web Applications (PWAs) will also be updated regularly, providing a more thorough understanding of the solutions that DockYard creates.&lt;/p&gt;

&lt;p&gt;âWe have many lessons learned that we hope to share with the community as a whole,â continues Cardarella. âOne of our primary missions at DockYard is to help improve the eco-system that we work in. Improvements to many of our Ember.js and Elixir libraries came out of this effort, and weâre excited to share these in the coming weeks.â&lt;/p&gt;

&lt;p&gt;For more information on DockYard and itâs services please visit &lt;a href=&quot;https://dockyard.com/services&quot;&gt;DockYard.com/services&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;DockYard is a software consultancy driven by creating exceptional user experiences.
By approaching software with the user experience at the forefront, DockYard delivers web applications that beat out native applications in any web browser using HTML5, CSS, and JavaScript.&lt;/p&gt;
</content>
  </entry><entry>
    <title>What type of business problem are we solving?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2017/04/17/what-business-problem-are-we-solving" />
    <id>https://dockyard.com/blog/2017/04/17/what-business-problem-are-we-solving</id>
    
    <published>2017-04-17 00:00:00</published>
    <updated>2017-04-26 09:53:50</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>The decision about where a problem &amp; solution belong within a business is as important as execution and quality.</summary>
    <content type="html">&lt;p&gt;Tl;dr: skills or expertise alone donât guarantee a great business outcome. You also need to know where to apply them.&lt;/p&gt;

&lt;p&gt;I was listening to &lt;a href=&quot;http://www.marketingforowners.com/podcast/595/&quot;&gt;an episode&lt;/a&gt; of &lt;em&gt;Marketing for Owners&lt;/em&gt; podcast recently, and one idea stopped me in my tracks. &lt;/p&gt;

&lt;p&gt;Kate Cook, a nutrition specialist, leads a consulting company focused on the benefits of nutrition. As part of her practice, she audits work environments from the nutritional health perspective, setting up educational programs and/or planning meals. Improving something like the food employees eat may seem like a nice-to-have and might often be treated casually. However, there is a different approach.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kate is often asked to go to a company and has done so under health and safety rather than employee wellness. Thatâs because youâre far more likely to have a manual handling accident if your blood sugar levels are not balanced. And that happens as a result of coming to work without breakfast and drinking energy drinks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.marketingforowners.com/podcast/595/&quot;&gt;source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea that struck me was this: &lt;strong&gt;the fact that Kateâs work is classified under Health &amp;amp; Safety can allow her to make a much bigger impact&lt;/strong&gt;. This is because the business can clearly see value in preventing accidents and improving safety. Accidents cause suffering, can stop work, increase insurance premiums, etc. etc..&lt;/p&gt;

&lt;p&gt;If the same specialistâs work is classified under âhuman resourcesâ instead, the impact can be limited by the scope and budget of that department. Human Resources deals with important issues, of course â but nutritional advice filed under HR could be interpreted as optional. The problem to be solved here is comfort, pleasure, and perhaps health. But without a clear connection to known important business goals (like health and safety) there will not be enough room in the budget to create an impactful nutritional program.&lt;/p&gt;

&lt;h2&gt;Itâs not just what you doâitâs where you do it.&lt;/h2&gt;

&lt;p&gt;My takeaway from listening to the podcast is this: the impact of my work is never defined by my skill or expertise alone. The impact of my work will be limited or multiplied by how itâs classified - what &lt;em&gt;type&lt;/em&gt; of business problem I am solving, in the clientâs eyes? &lt;/p&gt;

&lt;p&gt;Just like categorizing a nutrition program as âOptionalâ vs. âSafetyâ, you could think of design as something optional, or as something essential. Youâll get different results depending on your approach. &lt;/p&gt;

&lt;p&gt;You can expect better results if you have the opportunity to define not just the solution, but also the problem and where that problem belongs in the bigger picture of a business. A thoughtful, structured approach of a discovery frames both the problem and a proposed solution against a set of assumptions and constraints.&lt;/p&gt;

&lt;p&gt;When we bring in design after the problem has been fully defined, or even once itâs been partially solved, we reduce the potential impact. With a limited impact (for example, if we treat design as aesthetic-only) we can only justify a respectively smaller effort. &lt;/p&gt;

&lt;h2&gt;What this means for designers&lt;/h2&gt;

&lt;p&gt;As a practitioner, I know this understanding comes with experience. It took several years to see  how much the impact of design work depends on the âcategoryâ itâs been assigned by a client. You can be the best designer, but if thereâs a limited field to work in, you can only do so much. This can feel frustrating at times, but a good understanding of where you stand can help propose a right-size project instead of wasting time on an unnecessarily ambitious proposal, or under-estimating the impact your work can truly have.&lt;/p&gt;

&lt;h2&gt;What this means for business owners&lt;/h2&gt;

&lt;p&gt;For folks who are considering hiring design to solve a problem, itâs important to consider two things. One â the earlier you bring in design thinking - the larger potential impact it can have. Bring designers in at the planning stages to help define big wins for a project. And two â when you do collaborate with designers, at any stage, be honest about what âcategoryâ the project falls into within your business. Youâll support the design teamâs ability to think at the right level, right away, and get better answers to your questions around scope, time, and scale.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Improving Ember app page load times using the App Shell model</title>
    <link rel="alternate" href="https://dockyard.com/blog/2017/02/17/page-load-improvements-with-app-shell" />
    <id>https://dockyard.com/blog/2017/02/17/page-load-improvements-with-app-shell</id>
    
    <published>2017-02-17 00:00:00</published>
    <updated>2017-03-03 16:34:56</updated>
    <author><name>Marten Schilstra</name></author>
    <summary>Experimenting with the App Shell model to make the DockYard.com website load faster</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;In the past week I have been experimenting with the &lt;a href=&quot;https://developers.google.com/web/fundamentals/architecture/app-shell&quot;&gt;App Shell Model&lt;/a&gt; to make the &lt;a href=&quot;https://dockyard.com&quot;&gt;DockYard.com&lt;/a&gt; website load faster. In this blog post I&amp;#39;ll walk through which changes I made and how I&amp;#39;ve made them. Complete with some benchmarks!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Why improve page load speed?&lt;/h3&gt;

&lt;p&gt;According to Google, if &lt;a href=&quot;https://www.thinkwithgoogle.com/articles/mobile-page-speed-load-time.html&quot;&gt;loading a page takes too long&lt;/a&gt;, they&amp;#39;ll just abandon it. This hurts your conversion rates. Key metrics that contribute to better conversion rates are when the browser is able to make its first paint and when the page is fully loaded.&lt;/p&gt;

&lt;h3&gt;Tools of the trade&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;In this section I&amp;#39;ll introduce the tools I&amp;#39;ve used to measure the loading performance. Please take a minute to follow the links to the mentioned tools and read how they work and what they are for.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To be able to measure the performance of DockYard.com I have used &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/&quot;&gt;Lighthouse&lt;/a&gt; and the &lt;a href=&quot;https://developers.google.com/web/fundamentals/getting-started/codelabs/debugging-service-workers/&quot;&gt;Application&lt;/a&gt;, &lt;a href=&quot;https://developers.google.com/web/tools/chrome-devtools/network-performance/&quot;&gt;Network&lt;/a&gt; and &lt;a href=&quot;https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/timeline-tool&quot;&gt;Timeline&lt;/a&gt; DevTools from the Google Chrome team to see changes made a positive impact on loading speed.&lt;/p&gt;

&lt;p&gt;Lighthouse is the successor of Google&amp;#39;s &lt;a href=&quot;https://developers.google.com/speed/pagespeed/&quot;&gt;PageSpeed&lt;/a&gt; tool. Lighthouse uses your Chrome DevTool to do a host of automated audits. I.E. it checks if a &lt;a href=&quot;https://developers.google.com/web/fundamentals/getting-started/primers/service-workers&quot;&gt;Service Worker&lt;/a&gt; is registered and that a &lt;a href=&quot;https://developers.google.com/web/updates/2014/11/Support-for-installable-web-apps-with-webapp-manifest-in-chrome-38-for-Android&quot;&gt;Web App Manifest&lt;/a&gt; can be found. The audits I&amp;#39;m most interested in are the page load performance audits. These measure the &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint&quot;&gt;first meaningful paint&lt;/a&gt;, the &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/audits/speed-index&quot;&gt;speed index&lt;/a&gt; and &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive&quot;&gt;time to interactive&lt;/a&gt; performance.&lt;/p&gt;

&lt;h3&gt;What I&amp;#39;m measuring&lt;/h3&gt;

&lt;p&gt;I&amp;#39;m measuring the page load in two situations. The first situation is as if it&amp;#39;s the very first time I&amp;#39;m visiting the website, this means no assets have been cached yet. The second situation is when I&amp;#39;m loading the website on a repeat visit, which means the browser had a chance to cache the assets. I&amp;#39;ll also measure the same two scenarios using network and CPU throttling to simulate being out and about on a mobile device. Mobile simulation is done on the &amp;#39;Regular 3G&amp;#39; network throttling setting and the &amp;#39;Low end device&amp;#39; cpu throttling setting.&lt;/p&gt;

&lt;p&gt;There are three key performance metrics I&amp;#39;m looking for in each test, first I&amp;#39;ll look for when the first meaningful paint happens and second I&amp;#39;ll look for the moment when the Ember.JS app has booted client side and when the Ember.JS app has done its initial render on the client side. The first meaningful paint and the initial render metric are the two metrics that according to &lt;a href=&quot;https://www.thinkwithgoogle.com/articles/mobile-page-speed-load-time.html&quot;&gt;Google&lt;/a&gt; contribute the most to abandonment rate.&lt;/p&gt;

&lt;h3&gt;Getting the baseline&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Benchmarks have been made on a standard mid 2015 15&amp;quot; MacBook Pro, all tests have been done with a wired 500 megabit up/down internet connection. I have about 90ms latency towards the webserver and about 7ms to the assets server.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To start out, here are the baseline performance metrics of the current DockYard.com website. It is a Ember.js application that is served with &lt;a href=&quot;https://ember-fastboot.com&quot;&gt;FastBoot&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Baseline Lighthouse score&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/GNrFsfe.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Lighthouse measures without CPU slowdown and a custom network throttling setting&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This initial lighthouse score shows that the first meaningful paint comes just before the time to interactive. This does mean that when the page shows up, it&amp;#39;s almost immediately interactive, but you&amp;#39;ll see nothing before that.&lt;/p&gt;

&lt;h4&gt;Baseline Desktop: Page load with empty cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/pRF7ak0.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 600ms&lt;/li&gt;
&lt;li&gt;App boot: 1,175ms (the dip in the CPU graph)&lt;/li&gt;
&lt;li&gt;Initial render: 1,400ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Baseline Desktop: Page load with warmed cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/LQVYcYN.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 325ms&lt;/li&gt;
&lt;li&gt;App boot: 750ms&lt;/li&gt;
&lt;li&gt;Initial render: 950ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Baseline Mobile: Page load with empty cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/LNL0fSB.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 1,200ms&lt;/li&gt;
&lt;li&gt;App boot: 8,900ms&lt;/li&gt;
&lt;li&gt;Initial render: 10,200ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Baseline Mobile: Page load with warmed cache.&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/Z3Y9JZO.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 850ms&lt;/li&gt;
&lt;li&gt;App boot: 2,850ms&lt;/li&gt;
&lt;li&gt;Initial render: 4,200ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;The changes I&amp;#39;ve made&lt;/h3&gt;

&lt;p&gt;First off I&amp;#39;ve added (offline) caching by a Service Worker, using &lt;a href=&quot;http://ember-service-worker.com&quot;&gt;Ember Service Worker&lt;/a&gt; with various plugins. This did not, as expected, improve the cold boot scenarios, but did improve the scenarios with warmed cache slightly. Especially the first paint was much earlier. Results of the warmed cache scenarios are:&lt;/p&gt;

&lt;h4&gt;Service Worker only Desktop: Page load with warmed cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/oasoMXS.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 125ms&lt;/li&gt;
&lt;li&gt;App boot: 725ms&lt;/li&gt;
&lt;li&gt;Initial render: 900ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Service Worker only Mobile: Page load with warmed cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/Hq8beZk.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 300ms&lt;/li&gt;
&lt;li&gt;App boot: 2,700ms&lt;/li&gt;
&lt;li&gt;Initial render: 4,000ms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next I wrote a small &lt;a href=&quot;https://github.com/DockYard/ember-cli-one-script&quot;&gt;Ember CLI addon&lt;/a&gt; that concats both scripts (&lt;code&gt;vendor.js&lt;/code&gt; and &lt;code&gt;dockyard.js&lt;/code&gt;) that Ember CLI produces together. Then I proceeded to load that single JavaScript file using a `&lt;code&gt;element in the head that was marked&lt;/code&gt;async`. This had no significant improvement on the desktop side, but loading on mobile did improve. There is a small downside to this technique though, the two files aren&amp;#39;t cached seperately by the browser anymore, which can increase the amount of data needed to be transferred when deploying new builds often.&lt;/p&gt;

&lt;h4&gt;Async&amp;#39;ed script Mobile: Page load with empty cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/s6Uq246.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 750ms&lt;/li&gt;
&lt;li&gt;App boot: 7,950ms&lt;/li&gt;
&lt;li&gt;Initial render: 9,000ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Async&amp;#39;ed script Mobile: Page load with warmed cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/me4jkYA.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 200ms&lt;/li&gt;
&lt;li&gt;App boot: 2,350ms&lt;/li&gt;
&lt;li&gt;Initial render: 3,550ms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly I extracted all the critical CSS for an initial render and inlined it into the `` section. Then proceeded to asynchronously load the remaining CSS using &lt;a href=&quot;https://github.com/filamentgroup/loadCSS&quot;&gt;loaddCSS&lt;/a&gt;. This made the first paint come slightly earlier in all scenarios, but hurts the initial render by about 150ms on mobile.&lt;/p&gt;

&lt;h4&gt;Async&amp;#39;ed CSS Desktop: Page load with empty cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/IykzFzl.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 550ms&lt;/li&gt;
&lt;li&gt;App boot: 1.100ms&lt;/li&gt;
&lt;li&gt;Initial render: 1.325ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Async&amp;#39;ed CSS Desktop: Page load with warmed cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/jSl4eiJ.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 125ms&lt;/li&gt;
&lt;li&gt;App boot: 675ms&lt;/li&gt;
&lt;li&gt;Initial render: 900ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Async&amp;#39;ed CSS Mobile: Page load with empty cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/Y9vAfls.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 500ms&lt;/li&gt;
&lt;li&gt;App boot: 8,100ms&lt;/li&gt;
&lt;li&gt;Initial render: 9,150ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Async&amp;#39;ed CSS Mobile: Page load with warmed cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/j9JCLsg.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 125ms&lt;/li&gt;
&lt;li&gt;App boot: 2,500ms&lt;/li&gt;
&lt;li&gt;Initial render: 3,700ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;All the stats summed up in a table&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/7NTHg9u.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;h4&gt;Final Lighthouse score&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/B2dq8p5.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: To get the perfect 100/100 score we also added a Web App Manifest.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That&amp;#39;s an impressive 10x speed up in first paint and almost a second and a half in time to interactive. This gives your user much more confidence in that your page is loading.&lt;/p&gt;

&lt;h3&gt;Browsers without Service Worker&lt;/h3&gt;

&lt;p&gt;You might ask: &amp;quot;How does this affect page loading in browsers that not yet support Service Workers?&amp;quot;. I&amp;#39;ve tested the before and after with Safari&amp;#39;s timeline tool. The results show no significant speed up in full page load, but actually a slight slowdown. The results do show a significant speed up in first paint time with either empty or warm cache.&lt;/p&gt;

&lt;p&gt;After the benchmarks I&amp;#39;ve noticed that loading the service worker registration script plays a big part in the slowdown. I&amp;#39;d need to fiddle some more with loading that script to see if I can get rid of the slowdown.&lt;/p&gt;

&lt;p&gt;Below are the timeline graphs for loading in Safari. Notice the big shift of the blue &lt;code&gt;DOMContentLoaded&lt;/code&gt; line. That counts as the first paint. The red &lt;code&gt;Load&lt;/code&gt; line is the app boot. The last green bar is the initial render.&lt;/p&gt;

&lt;h4&gt;Baseline: Page load with empty cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/Skyo7Dk.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 510ms&lt;/li&gt;
&lt;li&gt;App boot: 600ms&lt;/li&gt;
&lt;li&gt;Initial render: 740ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;After improvements: Page load with empty cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/AZuSkqW.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 250ms&lt;/li&gt;
&lt;li&gt;App boot: 650ms&lt;/li&gt;
&lt;li&gt;Initial render: 820ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Baseline: Page load with warm cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/dE536q5.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 510ms&lt;/li&gt;
&lt;li&gt;App boot: 575ms&lt;/li&gt;
&lt;li&gt;Initial render: 730ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;After improvements: Page load with warm cache&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/QcDuWBI.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First paint: 250ms&lt;/li&gt;
&lt;li&gt;App boot: 620ms&lt;/li&gt;
&lt;li&gt;Initial render: 780ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Safari tests summarized&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/kZT1iWE.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;A Service Worker and a bit of techniques from the App Shell model can boost your page load times. Your app will show up on the screen earlier and be interactive quicker, which in turn can improve the conversion rates of your website.&lt;/p&gt;

&lt;p&gt;Please try out these techniques and see for yourself if it improves page load times of your app. In any case let me know how it works out for you.&lt;/p&gt;

&lt;p&gt;Closing: don&amp;#39;t forget to compress your images, svg&amp;#39;s and fonts! Those too can impact page load performance by seconds on mobile.&lt;/p&gt;
</content>
  </entry><entry>
    <title>How GenServer deals with errors in a concurrent environment</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/11/18/how-genserver-helps-to-handle-errors" />
    <id>https://dockyard.com/blog/2016/11/18/how-genserver-helps-to-handle-errors</id>
    
    <published>2016-11-18 00:00:00</published>
    <updated>2017-03-03 16:27:11</updated>
    <author><name>Daniel Xu</name></author>
    <summary>GenServer can help deal with race conditions, deadlocks, and many edge cases</summary>
    <content type="html">&lt;h2&gt;Pattern for stateful server process&lt;/h2&gt;

&lt;p&gt;After newcomers wrap their minds around immutability, they quickly question how to hold and change state in a language that
does not allow mutation. Elixir uses Erlang&amp;#39;s OTP libraries to formalize state access and mutation,
but to understand how this can happen in an immutable world we can implement our own stateful server using only a process with tail recursion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the following sample code, we define a start function which can be used to start the server process with an initial state.&lt;/li&gt;
&lt;li&gt;Because of &lt;code&gt;receive&lt;/code&gt;, the process will be blocked to wait for messages. Whenever clients send a message to the server process using &lt;code&gt;call&lt;/code&gt;,
it will pattern match on &lt;code&gt;{:message, caller, msg}&lt;/code&gt; and invoke the corresponding function to get the new state.&lt;/li&gt;
&lt;li&gt;After getting the new state, it replies to the client and runs the loop function from the beginning with the new state.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def start(inital_state) do
  spawn(fn -&amp;gt;
    initial_state = ...
    loop(initial_state)
  end)
end

defp loop(state) do
  receive do
    {:message, caller, msg} -&amp;gt;
      new_state = handle(msg, state)
      send(caller, {:reply, new_msg})
      loop(new_state)
    :stop -&amp;gt; terminate()
  end
end

def call(name_or_pid, message)
  send(name_or_pid, {:message, self(), message})
  receive do
    {:reply, reply} -&amp;gt; reply
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s simple but error-prone because we don&amp;#39;t handle any error condition. This becomes more complicated when dealing with a concurrent environment.
The good news is that &lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/GenServer.html&quot;&gt;GenServer&lt;/a&gt; can help deal with race conditions, deadlocks,
and many edge cases.&lt;/p&gt;

&lt;h2&gt;GenServer helps with error handling&lt;/h2&gt;

&lt;h3&gt;Ensure source of message using &lt;code&gt;reference&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;In the stateful server process above, the client sends a message to the server with a format of &lt;code&gt;{:message, pid_or_name, message}&lt;/code&gt;
and waits for a message with a format of &lt;code&gt;{:reply, reply}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As shown in the picture, the client might receive a similarly formatted reply from different servers,
how can we make sure that the reply is from the correct server?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://d.pr/i/BS8a+&quot; alt=&quot;msg&quot;&gt;&lt;/p&gt;

&lt;p&gt;The solution is to use &lt;strong&gt;a unique reference&lt;/strong&gt; to tag the message. when the client sends a request to the server,
it creates a unique reference first and sends it with its pid together: &lt;code&gt;{:message, {ref, pid}, message}&lt;/code&gt;,
and the server can reply with &lt;code&gt;{:reply, ref, reply}&lt;/code&gt;. This way, the client can pattern match based on the unique reference.&lt;/p&gt;

&lt;p&gt;Now, the &lt;code&gt;call&lt;/code&gt; function becomes:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def call(name_or_pid, message)
  ref = make_ref()
  send(name_or_pid, {:message, {ref, self()}, message})
  receive do
    {:reply, ^ref, reply} -&amp;gt; reply
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Erlang/OTP solves this problem with a unique reference as shown &lt;a href=&quot;https://github.com/erlang/otp/blob/maint/lib/stdlib/src/gen.erl#L167&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;What if the server crashes&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Server crashes before message is sent by client via server Pid&lt;/p&gt;

&lt;p&gt;If the server crashes before the message is sent from the client, the message will be lost and the client will be &lt;strong&gt;blocked&lt;/strong&gt; in the &lt;code&gt;receive&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;The solution is to monitor the server process using &lt;code&gt;Process.monitor(server_pid)&lt;/code&gt;. The reason why we choose &lt;code&gt;monitor&lt;/code&gt; instead of
&lt;code&gt;links&lt;/code&gt; is that monitor is unidirectional, so termination of the client will not affect the server.&lt;/p&gt;

&lt;p&gt;In case of a server crash, the client will receive a &lt;code&gt;Down&lt;/code&gt; message, so we can take action in the &lt;code&gt;receive&lt;/code&gt; block.
Noting that &lt;code&gt;monitor&lt;/code&gt; returns a reference, we can now drop the &lt;code&gt;make_ref()&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server crashes before message is sent by client via registered name&lt;/p&gt;

&lt;p&gt;In this case, the client process will terminate. To avoid crashing and return better error stack, we need to rescue the runtime error by
using &lt;code&gt;try...rescue&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server crashes right after replying to client&lt;/p&gt;

&lt;p&gt;If the server crashes right after it sends its reply to the client, a &lt;code&gt;Down&lt;/code&gt; message will be sent to the client&amp;#39;s
mailbox. The client, however, will never have a chance to pattern match this message because it &lt;code&gt;demonitors&lt;/code&gt; the server.&lt;/p&gt;

&lt;p&gt;This might cause memory leak and slow down the server. Ultimately, a single slow process may cause an entire system to crash by consuming all the available memory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Process.demonitor(ref, [:flush])&lt;/code&gt; is the solution for this issue. Every time we demonitor a server,
passing in a &lt;code&gt;flush&lt;/code&gt; option can make sure that any Down message that belongs to that monitor will be cleared.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After handling the server crash, the &lt;code&gt;call&lt;/code&gt; function looks like:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def call(name_or_pid, message, timeout \\ 5000)
  ref = Process.monitor(name_or_pid)
  try do
    send(name_or_pid, {:message, {ref, self()}, message})
  rescue
    _ -&amp;gt; :error
  end
  receive do
    {:reply, ref, reply} -&amp;gt;
      Process.demonitor(ref, [:flush])
      reply
    {:DOWN, ref, ...} -&amp;gt;
      {:error, reason}
      exit(reason)
    {:DOWN, ref, ..., :noconnection} -&amp;gt;
      node = get_node(name_or_pid)
      exit({:node_down, node})
  after timeout -&amp;gt; exit(:timeout)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Deadlock&lt;/h3&gt;

&lt;p&gt;If two processes synchronously call each other using the code above, both of them enter the &lt;code&gt;receive&lt;/code&gt; block which will cause
a &lt;a href=&quot;https://en.wikipedia.org/wiki/Deadlock&quot;&gt;Deadlock&lt;/a&gt;. This can be resolved with a timeout in the receive block. When the time is
out, the system can terminate the process and release the resources held by the process.&lt;/p&gt;

&lt;p&gt;An example is shown &lt;a href=&quot;https://github.com/erlang/otp/blob/maint/lib/stdlib/src/gen.erl#L178-L181&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There are a lot more concurrent errors that we haven&amp;#39;t discussed yet. Fortunately, GenServer handles all the concurrent conditions and
edge cases, we should almost always use it instead of reinventing the wheel.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Making a DDAU checkbox list in Ember.js</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/11/18/checkbox-list-ember" />
    <id>https://dockyard.com/blog/2016/11/18/checkbox-list-ember</id>
    
    <published>2016-11-18 00:00:00</published>
    <updated>2017-03-03 16:27:11</updated>
    <author><name>Nico Mihalich</name></author>
    <summary>Use Data Down, Actions Up to create a simple Checkbox List UI element in Ember</summary>
    <content type="html">&lt;h2&gt;Data Down, Actions Up (A refresher)&lt;/h2&gt;

&lt;p&gt;An important part of creating stable, maintainable Ember applications is following the Data Down, Actions Up (DDAU) paradigm.  This means that your data comes in at the route level and is displayed further down in your UI (by templates and components), while when you want to manipulate that data, you trigger an action which gets sent back up to the route that manipulate the data at its source.  This makes your application simple and easy to reason about because there is a single source of truth for your data and the route that manipulates the data.&lt;/p&gt;

&lt;h2&gt;Okay... so?&lt;/h2&gt;

&lt;p&gt;So, it&amp;#39;s hockey season! Let&amp;#39;s finally build that favorite player voting app you&amp;#39;ve always wanted. We&amp;#39;ll display a list of players via a list of checkboxes and have the user select which ones they like.  Our input will be a list of strings, and we want the output to be another list of strings. Following DDAU, ideally we want our checkboxes to not actually manipulate a &lt;code&gt;selected&lt;/code&gt; value directly, but send an action back up which manipulates our model and marks the player as &lt;code&gt;selected&lt;/code&gt;. (We&amp;#39;ll leverage &lt;a href=&quot;https://github.com/DockYard/ember-one-way-controls&quot;&gt;One Way Controls&lt;/a&gt; for that).&lt;/p&gt;

&lt;h2&gt;Setup&lt;/h2&gt;

&lt;p&gt;Model:
Our model hook is dead simple:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;model() {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; [];
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Also we&amp;#39;ll need some options to select from.  Let&amp;#39;s put that in the controller:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { Controller, set } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Controller.extend({
  init() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
    set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;playerOptions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, [
      &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Phil Kessel&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Sidney Crosby&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Tyler Seguin&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Steven Stamkos&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Connor McDavid&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Patrick Kane&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    ]);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And a simple template:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Pick your favorites&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;playerOptions&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;comment&quot;&gt;{{!TODO Checkbox}}&lt;/span&gt;
        &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;You picked&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Checkboxes&lt;/h2&gt;

&lt;p&gt;Now we have some options, and a place to select them into.  Let&amp;#39;s write the checkbox logic!  The API for a checkbox looks something like:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;one-way-checkbox&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;selected&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;update&lt;/span&gt;=&lt;span class=&quot;error&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;attribute-value&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;someAction&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Where selected is a boolean.&lt;/p&gt;

&lt;p&gt;For our use case, the checkbox should be selected when the player is in the model. Note our input and output are both lists of strings, no &lt;code&gt;selected&lt;/code&gt; attribute. So how do we mark it as selected if we don&amp;#39;t store it?&lt;/p&gt;

&lt;h2&gt;Quick detour into helpers!&lt;/h2&gt;

&lt;p&gt;We want to have &lt;code&gt;selected&lt;/code&gt; in our template be true when an item is in an array.  We can write a &lt;a href=&quot;https://guides.emberjs.com/v2.9.0/templates/writing-helpers/&quot;&gt;helper&lt;/a&gt; that does this for us which we can use in the template to return our &lt;code&gt;selected&lt;/code&gt; boolean value:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { &lt;span class=&quot;key&quot;&gt;Helper&lt;/span&gt;: { helper } } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;includes&lt;/span&gt;([haystack, needle]) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; haystack.includes(needle);
}

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; helper(includes);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This enables us to write&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;one-way-checkbox&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;includes&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s also useful in that if your model returns some options, the template is reactive to that and automatically marks them as selected because the helper is computing it from the higher up data flowing into it.&lt;/p&gt;

&lt;p&gt;Cool!&lt;/p&gt;

&lt;h2&gt;Actions&lt;/h2&gt;

&lt;p&gt;So far so good, but if we click on the checkbox... it doesn&amp;#39;t do anything.  We&amp;#39;ll need an update action, which we want in our route (using &lt;a href=&quot;https://github.com/DockYard/ember-route-action-helper&quot;&gt;ember-route-action-helper&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;  actions: {
    togglePlayer(player, checked) {
      let model = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;currentModel&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (checked) {
        model.pushObject(player);
      } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
        model.removeObject(player);
      }
    }
  }
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Finally&lt;/h2&gt;

&lt;p&gt;Now we can insert a checkbox using our &lt;code&gt;includes&lt;/code&gt; helper and action.&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;one-way-checkbox&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;includes&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;attribute-name&quot;&gt;update&lt;/span&gt;=&lt;span class=&quot;error&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;attribute-value&quot;&gt;route-action&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;togglePlayer&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And we&amp;#39;re done! &lt;a href=&quot;https://ember-twiddle.com/da6865aefe607e9deb460b5f29e20b0b&quot;&gt;Here&amp;#39;s a demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this demonstrates a practical example of DDAU in Ember to build a pretty common UI element.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Live Search with Ember &amp; JSON API</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/10/20/live-search-with-jsonapi" />
    <id>https://dockyard.com/blog/2016/10/20/live-search-with-jsonapi</id>
    
    <published>2016-10-20 00:00:00</published>
    <updated>2017-03-03 16:27:11</updated>
    <author><name>Romina Vargas</name></author>
    <summary>Build a JSON API-compliant live search using Ember and Phoenix/Rails</summary>
    <content type="html">&lt;p&gt;Live search is a feature commonly found in applications. There are various
solutions to implementing search functionality on a website, but &amp;quot;live search&amp;quot;
promotes a better user experience over the traditional way of searching
(i.e. type in keyword and click to view results); it&amp;#39;s satisfying to a user
since immediate feedback is received based on what they have typed, without
having to click some form of a &amp;quot;submit&amp;quot; or &amp;quot;search&amp;quot; button. It&amp;#39;s refreshing to
see results narrow as you type more words, or broaden as you backspace to delete
already-typed characters from the search box. The less work your user
has to do, the better.&lt;/p&gt;

&lt;p&gt;Live search is not new concept whatsoever, but if you&amp;#39;re new to the
&lt;a href=&quot;http://jsonapi.org/format&quot;&gt;JSON API specification&lt;/a&gt; and would like to follow its conventions,
this may be helpful.&lt;/p&gt;

&lt;p&gt;The specification states the following on the subject of filtering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;filter&lt;/code&gt; query parameter is reserved for filtering data.&lt;/li&gt;
&lt;li&gt;Servers and clients &lt;strong&gt;SHOULD&lt;/strong&gt; use this key for filtering operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given that info, we&amp;#39;ll go over how to set up the client-side (Ember), and the
server-side (in both Phoenix and Rails) to get live search working. In the
following examples, we&amp;#39;ll work with a &lt;code&gt;Food&lt;/code&gt; model having a &lt;code&gt;category&lt;/code&gt; attribute.&lt;/p&gt;

&lt;h2&gt;On the Ember side&lt;/h2&gt;

&lt;p&gt;To get started, make sure your application is using the &lt;code&gt;DS.JSONAPIADAPTER&lt;/code&gt;;
it&amp;#39;s the default adapter in a new Ember application. This informs your
application of the type of data that it should be expecting from the server. In
our case, the payload will be expected to have a specific format and will be
expected to contain certain keys. Check out the &lt;a href=&quot;http://jsonapi.org/format&quot;&gt;spec&lt;/a&gt; if you&amp;#39;d
like more details on this.&lt;/p&gt;

&lt;p&gt;Having that, we only need to add a couple of things:
&lt;a href=&quot;https://guides.emberjs.com/v2.8.0/routing/query-params/#toc_specifying-query-parameters&quot;&gt;query parameters&lt;/a&gt; and the call to the server itself.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// controllers/foods.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
const { Controller } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Controller.extend({
  &lt;span class=&quot;key&quot;&gt;queryParams&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;category&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// routes/foods.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
const { Route } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Route.extend({
  &lt;span class=&quot;key&quot;&gt;queryParams&lt;/span&gt;: {
    &lt;span class=&quot;key&quot;&gt;category&lt;/span&gt;: { &lt;span class=&quot;key&quot;&gt;refreshModel&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt; }
  },

  model(params) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.store.query(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;food&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;filter&lt;/span&gt;: { &lt;span class=&quot;key&quot;&gt;category&lt;/span&gt;: params.category } });
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s that simple. Notice that we&amp;#39;re using the store&amp;#39;s &lt;code&gt;query&lt;/code&gt; method and
providing it with a &lt;code&gt;filter&lt;/code&gt;. This &lt;code&gt;filter&lt;/code&gt; &lt;strong&gt;must&lt;/strong&gt; be included in the call.
This will result in a &lt;code&gt;GET&lt;/code&gt; request containing a URL encoded string with the
&lt;code&gt;filter&lt;/code&gt; query parameter:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/foods?filter%5Bcategory%5D=pastry&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now let&amp;#39;s see how to set this up on the backend for a seamless integration.&lt;/p&gt;

&lt;h2&gt;On the Phoenix side&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hex package needed: &lt;a href=&quot;https://github.com/AgilionApps/ja_resource&quot;&gt;ja_resource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Recommended to use with: &lt;a href=&quot;https://github.com/AgilionApps/ja_serializer&quot;&gt;ja_serializer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After following the lib&amp;#39;s quick installation instructions, and aside from
needing to add our route and schema, that&amp;#39;s all we need to do in Phoenix
before heading over to our controller for some filtering logic.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule MyApp.FoodController do
  import Ecto.Query

  use JaResource
  use MyApp.Web, :controller

  plug JaResource

  def filter(_conn, query, &amp;quot;category&amp;quot;, category) do
    from f in query,
      where: ilike(f.category, ^(&amp;quot;%#{category}%&amp;quot;))
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On L7, &lt;code&gt;plug JaResource&lt;/code&gt; is reponsible for providing all the controller actions
by default. There is no need for you to implement these actions unless you&amp;#39;d
like to add custom logic. That&amp;#39;s a pretty nice time saver!  Plus we can
customize our controller&amp;#39;s behavior via the many callbacks that the library
provides. JaSerializer conveniently provides the callback &lt;code&gt;filter/4&lt;/code&gt; where we
can handle our custom filtering given our filter parameters. In the example, we
only want to filter by category, so we add &amp;quot;category&amp;quot; as the third argument
so that we get a match. You&amp;#39;ll have to define one of these filter callbacks for
as many filter parameters as you want to pass. &amp;quot;Anything not explicitly matched
by your callbacks will get ignored.&amp;quot;&lt;/p&gt;

&lt;h2&gt;On the Rails side&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Gem needed: &lt;a href=&quot;https://github.com/cerebris/jsonapi-resources&quot;&gt;jsonapi-resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After having installed the gem, like in the Phoenix section above, you&amp;#39;ll need to
declare your routes and models. To gain the simplest form of the &lt;code&gt;filter&lt;/code&gt;
functionality, you just need to add the following (L5) to the corresponding
resource file (this will find an exact match):&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;FoodResource&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;JSONAPI&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Resource&lt;/span&gt;
  attributes &lt;span class=&quot;symbol&quot;&gt;:category&lt;/span&gt;

  filter &lt;span class=&quot;symbol&quot;&gt;:category&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The filter will be based on the term passed in from the &lt;code&gt;GET&lt;/code&gt; request coming
from the Ember side; it will make sure that we are only returned &lt;code&gt;Food&lt;/code&gt; records
whose &lt;code&gt;category&lt;/code&gt; value matches &lt;em&gt;exactly&lt;/em&gt; that of the request parameter
(i.e. &amp;quot;pastry&amp;quot;).&lt;/p&gt;

&lt;p&gt;Below, I show another example that leverages the &lt;code&gt;:apply&lt;/code&gt; option whose
arguments are records (an &lt;code&gt;ActiveRecord::Relation&lt;/code&gt;), the value to filter by,
and an options hash.  However, you have much flexibility on how you decide to
implement your filter. The &lt;a href=&quot;https://github.com/cerebris/jsonapi-resources#filters&quot;&gt;README filter section&lt;/a&gt;
has a more comprehensive list of the possibilities.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;FoodResource&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;JSONAPI&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Resource&lt;/span&gt;
  attributes &lt;span class=&quot;symbol&quot;&gt;:category&lt;/span&gt;

  filter &lt;span class=&quot;symbol&quot;&gt;:category&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;apply&lt;/span&gt;: -&amp;gt; (records, value, _options) {
   records.where(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;category LIKE ?&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;value[&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
  }
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;That wraps it up! The Ember frontend and the Phoenix/Rails backends now work
together to provide a live search functionality to a web application. Since
we&amp;#39;re following the JSON API spec, there is little to no friction on either
side in order to get this working as expected. Happy filtering!&lt;/p&gt;
</content>
  </entry><entry>
    <title>When you could turn a bug into a feature</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/10/19/bug-or-feature" />
    <id>https://dockyard.com/blog/2016/10/19/bug-or-feature</id>
    
    <published>2016-10-19 00:00:00</published>
    <updated>2017-03-03 16:59:49</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Understand why quirky behaviors are happening</summary>
    <content type="html">&lt;p&gt;My background often plays into what I pay attention to when assessing design projects. I grew up outside of the US - in Soviet Russia, where the proverbial [fill-in-the-blank] eats you. Iâve now spent about half my life in the US. This experience gives me a good amount of insight into both worlds, and just enough distance to question things.&lt;/p&gt;

&lt;h2&gt;âBugâ in behavior&lt;/h2&gt;

&lt;p&gt;One of my favorite things to explore is the meaning behind behavior oddities - small quirks we might often make fun of, or find âincorrectâ when we observe them in others. I see many of these in tech and web products, but first letâs explore an example from physical life, very analog indeed. &lt;/p&gt;

&lt;p&gt;When commuting on the metro in Moscow, I would often see folks reading a book wrapped protectively in newspaper. This trend would continue even after books have become relatively easy to find and purchase. The folks who continued the seemingly antiquated habit of wrapping books in newspaper tended to be older, and youâd be forgiven for chuckling at their behavior. &lt;em&gt;âTheyâre not with the times! Why would they inconvenience themselves by dealing with that unwieldy newspaper?â&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Bug or feature?&lt;/h2&gt;

&lt;p&gt;Look deeper. The newspaper wrapper doesnât just protect a bookâs surface. It gives the user a sense of safety and individuality. &lt;/p&gt;

&lt;p&gt;Books were a controversial item in Soviet Russia. A large portion of what is now considered classic Russian literature was censored. Censorship extended to encouraging citizens to snitch on others if they observe suspicious behavior. Reading a book in public was an invitation for others to check out what it is, and express an opinion. A camouflage behavior emerged: when reading anything more controversial than a gardening manual, or a state-issued newspaper, people would wrap the cover for privacy. &lt;/p&gt;

&lt;p&gt;How would you feel, knowing that your phone screen is clearly visible to everyone else on the train? Probably not that comfortable. To someone whoâs grown up 30 or so years ago in Russia, an exposed book cover would feel the same. Itâs a protective wrapper that gives us a bit of room to disagree with the system - and to avoid judgement.&lt;/p&gt;

&lt;p&gt;In my practice, Iâve seen plenty of examples of âbugsâ that reveal desired behaviors. For example, when redesigning a complex dashboard interface for specialist users, we noticed that the screen seemed overwhelmed with tabular data, almost to the point of being unreadable. It seemed like a quick visual design fix to reduce the clutter and show less information to help people focus. But that âbugâ revealed a level of comfort the users had with seeing all of the information at once. They actually preferred the high density of information in some parts of the experience, because it matched an existing workflow in Excel, and reduced the cognitive load of switching back and forth.&lt;/p&gt;

&lt;h2&gt;Tl;dr.&lt;/h2&gt;

&lt;p&gt;Quaint behaviors that donât make sense are a signal. When we observe them, we should know thereâs more to discover. Something that looks like a bug to a design practitioner, can lead to a valuable feature in the eyes of a specialized user. &lt;/p&gt;

&lt;p&gt;We should train ourselves to see these little âbugsâ in othersâ habits as opportunities to discover a deeper motivation, then build uniquely useful products as a result. And learn a fun fact for a blog post!&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Role of Discovery Phases and Design Sprints</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/10/06/the-role-of-discovery-phases-and-design-sprints" />
    <id>https://dockyard.com/blog/2016/10/06/the-role-of-discovery-phases-and-design-sprints</id>
    
    <published>2016-10-06 00:00:00</published>
    <updated>2017-03-03 16:59:49</updated>
    <author><name>Patrick Branigan</name></author>
    <summary>Understanding what they are and when to use them</summary>
    <content type="html">&lt;p&gt;In terms of design processes, there are two that have proven to be integral parts to building a project: the Discovery 
Phase and the Design Sprint. Both provide vital information and guidance in the pursuit of bringing an idea to fruition. 
However there are occasions when it can be difficult to decide which to employ. Do you need one or the other? Do you need 
both? &lt;/p&gt;

&lt;p&gt;First, we need to remind ourselves of the definition and purpose of each process and better educate clients on the two.&lt;/p&gt;

&lt;h2&gt;What are they?&lt;/h2&gt;

&lt;p&gt;In essence a Discovery Phase is an interval of time in which a team focuses on exploring the ins and outs of an existing 
product and identifying its impact on a clientâs bottom line. We use Discovery Phases to discover untapped value. This is 
done by executing an array of exercises ranging from stakeholder interviews to user interviews, from personas to journey 
maps. At its end, a client is provided opportunistic suggestions on how to improve on an existing product in ways that add 
value to their company and/or their customers.&lt;/p&gt;

&lt;p&gt;In regards to a Discovery Phase, itâs important to recognize that while this processâ deliverable might take many forms, its 
purpose is primarily to audit and recommend, not necessarily to build and implement. Instead, part of the deliverable might 
be specific options for designing, building and implementing the recommendations.&lt;/p&gt;

&lt;p&gt;While a Discovery Phase is focused on review of existing products, a Design Sprint is intended to be utilized when there is 
a need for something new â new products, features, services, etc. It is a methodology of agile product design that revolves 
most heavily around end users. We design, prototype and test ideas with users to validate or invalidate new products, 
features and services whose value is solving business questions. At its end, a client is witness to a new idea come to life 
and put in front of their users in the hopes of rapid validation or invalidation. This product, feature or service is 
intended to show value quickly or otherwise fail quickly, saving time and resources that otherwise might have been spent on 
a more robust build. &lt;/p&gt;

&lt;p&gt;In regards to a Design Sprint, itâs important to recognize that its purpose is to allow for rapid validation or failure of a 
product (or feature, service, etc.) which requires user involvement and feedback.&lt;/p&gt;

&lt;p&gt;While there are some similarities in how the two processes are carried out, their intent is quite different. This difference 
becomes especially clear  when we look at the staples of a design project lifecycle: the time it takes, whatâs being 
produced and the people involved.&lt;/p&gt;

&lt;p&gt;With a better understanding of the two, we can better dictate with our clients whether to conduct a Discovery Phase or a 
Design Sprint (and when not to).&lt;/p&gt;

&lt;h2&gt;Differentiating the Two&lt;/h2&gt;

&lt;h4&gt;Length (time)&lt;/h4&gt;

&lt;p&gt;Discovery Phases and Design Sprints are often drastically different in terms of the amount of time needed to complete each. 
While a Design Sprint is modeled within one weekâs time, a Discovery Phase can take as little as 1 week or up to 8 weeks to 
complete depending on the project size, complexity, familiarity and goals. Sprints can be repeated, but they follow the same routine and still focus on validating or invalidating a narrowed idea or question.&lt;/p&gt;

&lt;h4&gt;Structure (time)&lt;/h4&gt;

&lt;p&gt;A Discovery Phase might call for very mild quantitative research or it might require a plethora of user research methods to 
be carried out. Because of the variability from project to project, the organization and scheduling of a Discovery Phase 
often requires a much more custom approach than the Design Sprint. A Design Sprint, due to the nature of its deliverable, 
generally follows a similar structure each and every time. A Discovery Phase has us discover, research, assess, report and 
recommend ideas via an array of design research methods. A Design Sprint has us map, sketch, storyboard, prototype and user 
test in the same or similar structured approach each time.&lt;/p&gt;

&lt;h4&gt;Completion (deliverable)&lt;/h4&gt;

&lt;p&gt;A Discovery Phase can generally be considered complete when the variables surrounding the existing challenge, and the way 
forward for the product, are defined. What are the goals? Have we identified not just whatâs wanted but whatâs needed? 
Whatâs the scope of the challenges uncovered and the solutions proposed? How are the outcomes of these solutions going to be 
measured? &lt;/p&gt;

&lt;p&gt;A Design Sprint can generally be considered complete when users have validated or invalidated the product, feature or 
service to be built via testing prototypes. Was this product, feature, service, etc. desired by users? Did users achieve 
their goals? What patterns surfaced from interviews and tests? What can we do better? What have we learned?&lt;/p&gt;

&lt;h4&gt;Expertise (team)&lt;/h4&gt;

&lt;p&gt;In both a Discovery Phase and a Design Sprint itâs important to bring the right team together. In a Discovery Phase we want 
stakeholders such as owners, designers, developers, business analysts, service reps, etc. who can identify problems to be 
solved. Yes, in a Design Sprint we might involve these entities as well, but we need to involve users who can validate 
solutions to the challenges weâre trying to solve. &lt;/p&gt;

&lt;p&gt;Understanding the general differences between a Discovery Phase and a Design Sprint will help in deciphering which one is 
needed and when, as well as when and to whom to sell these processes. What are some things to look for when determining if 
you should pursue a Discovery Phase or a Design Sprint? &lt;/p&gt;

&lt;h2&gt;Deciding Between the Two&lt;/h2&gt;

&lt;p&gt;Generally, the broader the scope of the challenge the less likely a team is in a position to do a Design Sprint. Instead, 
one might consider engaging in a Discovery Phase to narrow a problem area first. Then, consider Design Sprints to prototype 
and test primary solutions to a target facet of that narrowed problem. For example, asking to âreinvent the way in which we 
communicateâ might be a tall order for a week long Design Sprint, and more so a discussion suited for Discovery. &lt;/p&gt;

&lt;p&gt;The value of a Discovery Phase to a business owner its ability to provide a crystal-clear understanding of what their 
company, product or service needs in order to advance and increase value moving forward. Itâs a hands-on experience that 
will give everyone involved the tools and insight they need to make informed decisions about the future of their product or 
service.&lt;/p&gt;

&lt;p&gt;In order to focus in on a Design Sprint there generally needs to be a significant amount of input to draw from. This would 
mean design research data should already exist, particularly in regards to users. Interviews, personas, journeymaps, 
ethnography, etc. should be considered prior to a Design Sprint, often within Discovery. However if these already exist, 
one might consider using a Sprint.&lt;/p&gt;

&lt;p&gt;The value of a Design Sprint to a business owner is itâs ability to bring an idea to life and then validate or invalidate 
it quickly. This is because its structure allows for failure to happen without wasting resources, therefore quickly 
invalidating ideas. Yet it provides a rapid and solid foundation for beginning development on validated ideas. The time and 
effort spent on validation or invalidation is significantly less, therefore potentially saving business owners large 
amounts of money when chasing prospective innovation.&lt;/p&gt;
</content>
  </entry><entry>
    <title>How to Contribute to Ember</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/09/30/how-to-contribute-to-ember" />
    <id>https://dockyard.com/blog/2016/09/30/how-to-contribute-to-ember</id>
    
    <published>2016-09-30 00:00:00</published>
    <updated>2016-10-04 14:54:32</updated>
    <author><name>Doug Yun</name></author>
    <summary>A brief guide on how to contribute to open source software</summary>
    <content type="html">&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;There are numerous ways to contribute to open source software. You can do one of
the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Engage, Help and Teach&lt;/li&gt;
&lt;li&gt;Write articles and improve learning resources&lt;/li&gt;
&lt;li&gt;Create and comment on issues&lt;/li&gt;
&lt;li&gt;Contribute code&lt;/li&gt;
&lt;li&gt;Build the community&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Today, we&amp;#39;ll use Ember as an example. To find out ways to aid the Ember community,
read more below!&lt;/p&gt;

&lt;h2&gt;Open Source is Used by Everyone&lt;/h2&gt;

&lt;p&gt;A majority of the tools we use at DockYard are open source software (OSS) and we
love &lt;a href=&quot;https://github.com/dockyard&quot;&gt;giving back to the community&lt;/a&gt;. If you&amp;#39;re reading this post,
the chances that you are using OSS are pretty darn high. Just take a look at the
Wikipedia page for &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_free_and_open-source_software_packages&quot;&gt;the list of free and open source software packages&lt;/a&gt;.
It&amp;#39;s safe to say that OSS is used by a bizallion companies each day!&lt;/p&gt;

&lt;h2&gt;Examples of OSS at DockYard&lt;/h2&gt;

&lt;p&gt;Some highlights of DockYard&amp;#39;s current stack includes &lt;a href=&quot;http://elixir-lang.org/&quot;&gt;Elixir&lt;/a&gt;,
&lt;a href=&quot;http://phoenixframework.org&quot;&gt;Phoenix&lt;/a&gt;, and &lt;a href=&quot;http://emberjs.com&quot;&gt;Ember&lt;/a&gt;. Not only do we utilize these
tools to build &lt;a href=&quot;https://dockyard.com/work&quot;&gt;amazing applications&lt;/a&gt;, we also contribute back to these
fantastic organizations.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;re interested in Elixir, I recommend checking out Brian&amp;#39;s post entitled
&lt;a href=&quot;https://dockyard.com/blog/2016/02/02/how-to-contribute-to-elixir&quot;&gt;How to contribute to Elixir&lt;/a&gt;. In that post, he goes over his
experience contributing code to the language.&lt;/p&gt;

&lt;h2&gt;Cheesy Call to Action: What Can You Do?&lt;/h2&gt;

&lt;p&gt;Today, we&amp;#39;ll touch upon a few basic ways to contribute back to the Ember community.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;re a beginner to open source, have no fear! I have had the great fortune
of working with some amazing OSS contributors, who all started out inexperienced,
yet, have grown to become open source powerhouses.&lt;/p&gt;

&lt;h2&gt;Let&amp;#39;s Start Contributing (to Ember)&lt;/h2&gt;

&lt;p&gt;Ember has been around for while (some say as early as 2011), and as expected,
has greatly matured. From recommended tools to best practices, Ember&amp;#39;s
ever improving wave has been a wild, yet relatively safe ride. I&amp;#39;ve been working
with Ember before it was cool, and can share my personal experience
with helping out the community.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Y2Zr7NA.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks, &lt;a href=&quot;https://twitter.com/habdelra&quot;&gt;Hassan&lt;/a&gt; for the hilarious infuriated Tomster&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Engage, Help and Teach&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;http://emberjs.com/community/&quot;&gt;Ember community page&lt;/a&gt; lists various places where users
can chat, discuss, or ask questions. However, it should be noted that from my experience,
IRC and discussion forum do not receive as much traffic as the &lt;a href=&quot;https://ember-community-slackin.herokuapp.com/&quot;&gt;Slack community&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I recommend using the Slack community as the number one communication resource.
There are numerous channels that range from local user groups to
testing practices. I suggest examining the channels you&amp;#39;d like to belong to, and engage with
fellow users.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;#-help&lt;/code&gt; channel is a great place to ask Ember-related questions.
Furthermore, there are plenty of opportunities to help and teach your fellow developers
about Ember.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Hxw1qtd.png&quot; alt=&quot;&quot;&gt;
&lt;em&gt;A real life enactment of someone helping another person in the Ember Slack community&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Write articles and improve learning resources&lt;/h3&gt;

&lt;p&gt;I have read my fair share of articles based upon web development (I have stopped
reading any articles about JavaScript fatigue though). I imagine many of us have
learned a great deal from articles detailing one cool trick by a seasoned developer,
or an article describing the pros and cons of a given programming language.
My point is that so many of us learn from consuming blog posts, articles, etc.&lt;/p&gt;

&lt;p&gt;So, add to the sea of knowledge, and write something you know about. Heck,
I&amp;#39;m doing that right now! And, if someone has &lt;a href=&quot;http://madhatted.com/2014/11/5/contribute-to-ember-js-2-0-no-coding-required&quot;&gt;already written about a topic
you care about&lt;/a&gt;, perhaps you can offer another perspective
or additional advice.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://guides.emberjs.com/&quot;&gt;Ember guides&lt;/a&gt; are &lt;a href=&quot;https://github.com/emberjs/guides&quot;&gt;open sourced on GitHub&lt;/a&gt;,
and there are plenty of &lt;a href=&quot;https://github.com/emberjs/guides/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22&quot;&gt;issues marked as &amp;quot;help-wanted&amp;quot;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Create and Comment On Issues&lt;/h3&gt;

&lt;p&gt;Just like any other open source project, Ember and its associated libraries, receive
a &lt;a href=&quot;https://github.com/emberjs/ember.js/issues&quot;&gt;high number issues&lt;/a&gt;. Luckily, we can help out!&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s say you happen to run into a &amp;quot;bug&amp;quot;, what should you do next? First, search through
the existing issue tracker for the given project, and &lt;a href=&quot;https://xkcd.com/979/&quot;&gt;attempt to find your issue&lt;/a&gt;.
If you find your issue, add a comment!&lt;/p&gt;

&lt;p&gt;Thorough comments on a particular issue can help tremendously. If you see a comment, and
are experiencing the same issue, please don&amp;#39;t bombard the maintainers with a &amp;quot;+1&amp;quot; comment.
Instead, offer something more insightful. You can attach an &lt;a href=&quot;https://ember-twiddle.com/&quot;&gt;Ember Twiddle&lt;/a&gt;
in an effort to recreate the issue, and state your expectation vs. actual behavior.&lt;/p&gt;

&lt;p&gt;If you can&amp;#39;t find an existing issue that replicates yours, create a new one.
Ember actually has a &lt;a href=&quot;https://github.com/emberjs/ember.js/blob/master/CONTRIBUTING.md#issues&quot;&gt;good recommendation on issue reporting&lt;/a&gt;.
Following these steps helps to ensure that your issue can be recreated and corrected
as soon as possible. Moreover, it opens up the opportunity for others from the community
to solve your issue.&lt;/p&gt;

&lt;h3&gt;Contribute Code&lt;/h3&gt;

&lt;p&gt;Submitting &lt;a href=&quot;https://github.com/emberjs/ember.js/blob/master/CONTRIBUTING.md#pull-requests&quot;&gt;pull requests to Ember libraries is straightforward&lt;/a&gt;.
There is a channel within the Slack community called &lt;code&gt;dev-ember&lt;/code&gt; that is reserved
for the discussion of &amp;quot;development on Emberjs itself.&amp;quot;&lt;/p&gt;

&lt;p&gt;So long as you follow the aforementioned guidelines, submitting a PR is an easy
process.&lt;/p&gt;

&lt;p&gt;Just like any other code base, Ember libraries can be intimidating at first, however
with enough persistence, you&amp;#39;ll be cooking in no time! In addition, &amp;quot;contributing
code&amp;quot; can take the form of &lt;a href=&quot;https://github.com/emberjs/ember.js/labels/Documentation&quot;&gt;contributing documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, if you stick around, the maintainers occasionally ask for community help,
and you&amp;#39;ll be rewarded with a great opportunity to help out.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/KRQr2p6.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Please Ember community... you&amp;#39;re my only hope&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Build the community&lt;/h3&gt;

&lt;p&gt;When I say building the community, I mean you don&amp;#39;t necessarily need to go
out and create a whole new meetup, or start a brand new conference (though
those are all good things). There are other less exhausting methods of
building and improving the Ember community.&lt;/p&gt;

&lt;p&gt;There are various meetups to join, and plenty of ways to contribute.
Submitting a talk - whether it is a conference proposal or a lightning talk -
will allow you to broadcast your experiences with Ember, and help generate new discussions.
Secondly, I enjoy attending local meetups and conferences as it gives me the chance to
place faces with GitHub, Twitter, and Slack handles.&lt;/p&gt;

&lt;h2&gt;Fin&lt;/h2&gt;

&lt;p&gt;Hope you found this article helpful! And before you go, our entire blog is open sourced,
so if you find a typo or want to make a suggestion, &lt;a href=&quot;https://github.com/dockyard/reefpoints&quot;&gt;please feel free&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Retiring Ember Suave</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/09/30/retiring-ember-suave" />
    <id>https://dockyard.com/blog/2016/09/30/retiring-ember-suave</id>
    
    <published>2016-09-30 00:00:00</published>
    <updated>2016-10-04 14:54:32</updated>
    <author><name>Estelle DeBlois</name></author>
    <summary>Following the merge of JSCS with ESLint, `ember-suave` now has a new successor.</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;&amp;quot;The role of style in programming is the same as in literature: It makes for better reading. A great writer doesn&amp;#39;t express herself by putting the spaces before her commas instead of after, or by putting extra spaces inside her parentheses. A great writer will slavishly conform to some rules of style, and that in no way constrains her power to express herself creatively.&amp;quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While the writer analogy taken from Douglas Crockford&amp;#39;s much rigid &lt;a href=&quot;https://github.com/douglascrockford/JSLint&quot;&gt;JSLint&lt;/a&gt; may hold true for the English language, even something as simple as a space can follow different rules in different parts of the world. For instance, in French, the exclamation point is always preceded by a space.&lt;/p&gt;

&lt;p&gt;In the world of code, it matters less whether you are a fan of semi-colons first, or whether you favor &lt;a href=&quot;https://www.youtube.com/watch?v=SsoOG6ZeyUI&quot;&gt;tabs over spaces&lt;/a&gt; (except that we all know one is right and the other is wrong); what matters is that code style is consistent within a team, and that there is a way to enforce it.&lt;/p&gt;

&lt;h2&gt;The rise of &lt;code&gt;ember-suave&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;When my fellow DockYarders and I originally decided to make code style checking a part of our regular Ember CLI development workflow, &lt;a href=&quot;http://jscs.info/&quot;&gt;JSCS&lt;/a&gt; was the de facto code style checker. We thus set out to build &lt;a href=&quot;https://github.com/DockYard/ember-suave&quot;&gt;&lt;code&gt;ember-suave&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The addon used &lt;a href=&quot;https://github.com/kellyselden/broccoli-jscs&quot;&gt;&lt;code&gt;broccoli-jscs&lt;/code&gt;&lt;/a&gt; internally, but it also shipped with an already configured set of JSCS rules as well as custom rules we had written. We wanted it to be opinionated, something that we could simply drop into any of our Ember CLI projects and start coding against. We wanted to put the S in Suave.&lt;/p&gt;

&lt;p&gt;We also made the preset configurable with the hope that it would be usable by anyone outside of DockYard who might be looking for a quick jump start on JSCS, since they would only need to overwrite those rules that do not align with their team&amp;#39;s style guide. It turns out that &lt;code&gt;ember-suave&lt;/code&gt; did end up being used across a sizeable number of &lt;a href=&quot;https://github.com/search?l=&amp;amp;p=3&amp;amp;q=ember-suave+extension%3Ajson&amp;amp;ref=advsearch&amp;amp;type=Code&amp;amp;utf8=%E2%9C%93&quot;&gt;projects&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For all those folks, I would like to announce at last that we are retiring &lt;code&gt;ember-suave&lt;/code&gt;. This means that we will no longer build custom rules for it or enhance it in any way, and that it may just as well find its way into &lt;a href=&quot;https://github.com/DavyJonesLocker&quot;&gt;Davy Jones&amp;#39; Locker&lt;/a&gt;, which is where all abandoned DockYard open-source projects go to die.&lt;/p&gt;

&lt;h2&gt;JSHint, JSCS, and ESLint&lt;/h2&gt;

&lt;p&gt;JSCS reached &lt;a href=&quot;http://eslint.org/blog/2016/07/jscs-end-of-life&quot;&gt;end-of-life&lt;/a&gt; back in July, three months after joining up with &lt;a href=&quot;http://eslint.org/&quot;&gt;ESLint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a bit of history, when &lt;a href=&quot;http://jshint.com/about/&quot;&gt;JSHint&lt;/a&gt; started focusing strictly on functional rules, JSCS emerged as the static analysis tool for all stylistic concerns in JavaScript. This was sometime back in 2013. For the longest time, JSHint and JSCS complemented each other rather well.&lt;/p&gt;

&lt;p&gt;Meanwhile, Nicholas Zakas &lt;a href=&quot;https://www.nczonline.net/blog/2013/07/16/introducing-eslint/&quot;&gt;created&lt;/a&gt; ESLint as a fully pluggable alternative to JSHint. As ESLint and JSCS matured and grew in popularity, the two projects started overlapping in functionality and goals, so instead of continuing to lead separate ways, they joined up. You can read more about the merge &lt;a href=&quot;http://eslint.org/blog/2016/04/welcoming-jscs-to-eslint&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;&lt;code&gt;ember-suave&lt;/code&gt; returns as an ESLint plugin&lt;/h2&gt;

&lt;p&gt;Most of the rules from &lt;code&gt;ember-suave&lt;/code&gt;, including the custom ones, have been converted to ESLint in a new repo called &lt;a href=&quot;https://github.com/DockYard/eslint-plugin-ember-suave&quot;&gt;&lt;code&gt;eslint-plugin-ember-suave&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The biggest difference is that you are no longer looking at an Ember CLI addon. &lt;code&gt;eslint-plugin-ember-suave&lt;/code&gt;, as its name implies, is simply an ESLint plugin (the equivalent of a JSCS preset). It&amp;#39;s just a collection of custom rules and their configuration, as well as configuration of additional rules already built into ESLint.&lt;/p&gt;

&lt;p&gt;In order to run ESLint with the supplied configuration, you will need to install the &lt;a href=&quot;https://github.com/ember-cli/ember-cli-eslint&quot;&gt;&lt;code&gt;ember-cli-eslint&lt;/code&gt;&lt;/a&gt; addon into your Ember project. It is worth noting that doing so will also uninstall any existing installation of &lt;a href=&quot;https://github.com/ember-cli/ember-cli-jshint&quot;&gt;&lt;code&gt;ember-cli-jshint&lt;/code&gt;&lt;/a&gt;, since it doesn&amp;#39;t make sense to use both linters simultaneously.&lt;/p&gt;

&lt;h2&gt;The joy of having contributors&lt;/h2&gt;

&lt;p&gt;Migrating &lt;code&gt;ember-suave&lt;/code&gt; over to an ESLint plugin had been a lingering goal for quite some time. I just happened to have limited time to devote to it. To that end, I have contributors to thank, particularly &lt;a href=&quot;https://github.com/alexlafroscia&quot;&gt;Alex LaFroscia&lt;/a&gt;, for spearheading the effort. He rewrote all the JSCS custom rules we had in &lt;code&gt;ember-suave&lt;/code&gt; to their ESLint equivalents. &lt;a href=&quot;https://github.com/rwwagner90&quot;&gt;Robert Wagner&lt;/a&gt; also landed a hand in accelerating the development of the plugin, at a time when I was mostly taking a hands-off stance due to maternity leave. I do appreciate that they motivated me to code every now and then, as much as it was challenging to pair program with a two-month old.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Understanding Ember&#39;s resolver</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/09/14/understanding-ember-s-resolver" />
    <id>https://dockyard.com/blog/2016/09/14/understanding-ember-s-resolver</id>
    
    <published>2016-09-14 00:00:00</published>
    <updated>2016-09-14 14:36:43</updated>
    <author><name>Marten Schilstra</name></author>
    <summary>An introduction to how Ember&#39;s resolver works</summary>
    <content type="html">&lt;p&gt;Ember&amp;#39;s &lt;a href=&quot;https://guides.emberjs.com/v2.8.0/applications/dependency-injection/&quot;&gt;dependency injection&lt;/a&gt; system is driven by a resolver.
It is used to lookup JavaScript modules agnostic from what kind of module system is used, which can be AMD, CommonJS or just plain globals.
A resolver works based on a set of rules, which reflects how Ember apps are structured.&lt;/p&gt;

&lt;h2&gt;How the resolver is used&lt;/h2&gt;

&lt;p&gt;The resolver is used widely throughout an Ember application.
It is used to lookup routes, models, components and much more.&lt;/p&gt;

&lt;p&gt;When your Ember app transitions into a route, the resolver is used to find the corresponding route module. 
For example: if you navigate to &lt;code&gt;/blog&lt;/code&gt;, then the blog route needs to be looked up. 
This is done by asking the resolver to resolve &lt;code&gt;route:blog&lt;/code&gt;, this will resolve a module named &lt;code&gt;blog&lt;/code&gt; of type &lt;code&gt;route&lt;/code&gt;.
After the route is done loading the model, we need a controller, so we ask the resolver for &lt;code&gt;controller:blog&lt;/code&gt;. 
Lastly a template needs to be rendered, so once again we go to the resolver and ask for &lt;code&gt;template:blog&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same thing happens when rendering a component. First the resolver is asked for &lt;code&gt;component:my-component&lt;/code&gt;,
then &lt;code&gt;template:component/my-component&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;The rules of the resolver&lt;/h2&gt;

&lt;p&gt;Today the resolver is used the most to resolve modules using Ember CLI&amp;#39;s AMD module system.
So I&amp;#39;m going to use that in the next few examples.&lt;/p&gt;

&lt;h3&gt;The prefix&lt;/h3&gt;

&lt;p&gt;First of all, a resolver requires a &lt;code&gt;modulePrefix&lt;/code&gt; variable.
This variable is found in the &lt;code&gt;config/environment&lt;/code&gt; file of an Ember CLI app and is being passed to the resolver by your Ember application.
You should also know that the &lt;code&gt;app/routes/blog.js&lt;/code&gt; file in your Ember CLI app gets a different path in the compiled output.
The &lt;code&gt;app&lt;/code&gt; part of the path is replaced by the &lt;code&gt;modulePrefix&lt;/code&gt; variable. So our example would become &lt;code&gt;my-app/routes/blog&lt;/code&gt; if our &lt;code&gt;modulePrefix&lt;/code&gt; variable is &lt;code&gt;my-app&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Dissecting a resolver statement&lt;/h3&gt;

&lt;p&gt;The resolver disects the statement &lt;code&gt;route:blog&lt;/code&gt; into two parts, a type (&lt;code&gt;route&lt;/code&gt;) and a name (&lt;code&gt;blog&lt;/code&gt;). Those parts are then translated into a path which can be used to load a module.
In the case of Ember CLI&amp;#39;s AMD modules it would give you &lt;code&gt;my-app/routes/blog&lt;/code&gt;, which is constructed of &lt;code&gt;modulePrefix&lt;/code&gt; / &lt;code&gt;type&lt;/code&gt; (pluralized) / &lt;code&gt;name&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The resolver can also easily resolve things nested inside subfolders.
For example, &lt;code&gt;template:component/my-component&lt;/code&gt;, it&amp;#39;ll be resolved to &lt;code&gt;my-app/templates/components/my-component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also make up your own type, it doesn&amp;#39;t have to be one of Ember&amp;#39;s types.
For example, &lt;a href=&quot;https://github.com/DockYard/ember-validations&quot;&gt;Ember Validations&lt;/a&gt; uses the resolver to look up modules of the &lt;code&gt;validator&lt;/code&gt; type.&lt;/p&gt;

&lt;h3&gt;Resolving addon modules&lt;/h3&gt;

&lt;p&gt;The resolver has one more trick up its sleeve, it can resolve things outside of your app using a custom &lt;code&gt;modulePrefix&lt;/code&gt;.
If you prefix the statement asked to the resolver with your custom &lt;code&gt;modulePrefix&lt;/code&gt; and an &lt;code&gt;@&lt;/code&gt;, then it&amp;#39;ll replace the configured &lt;code&gt;modulePrefix&lt;/code&gt; with yours.
The statement &lt;code&gt;an-addon@component:x-utility&lt;/code&gt; would be resolved to &lt;code&gt;an-addon/components/x-utility&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Some exceptions&lt;/h3&gt;

&lt;p&gt;The resolver has some exceptions built in, to resolve a few special things. 
Anything with &lt;code&gt;main&lt;/code&gt; as the name part will resolve without the name in the resulting module name.
So &lt;code&gt;router:main&lt;/code&gt; will resolve to &lt;code&gt;my-app/router&lt;/code&gt;, leaving out the name part. The same rule applies to &lt;code&gt;store:main&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;The resolver is a fairly straightforward abstraction that helps you resolve modules, agnostic from all the various module loading systems.
If you get to know how it works it can be a great new tool in your arsenal.&lt;/p&gt;
</content>
  </entry><entry>
    <title>KISS by Example: Authorization in Phoenix</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/09/08/kiss-phoenix-auth" />
    <id>https://dockyard.com/blog/2016/09/08/kiss-phoenix-auth</id>
    
    <published>2016-09-08 00:00:00</published>
    <updated>2016-10-04 14:54:32</updated>
    <author><name>Nico Mihalich</name></author>
    <summary>A short example of authorization in Phoenix to show how modules, functions, and pattern matching can easily fill a common web application need.</summary>
    <content type="html">&lt;h2&gt;Modules, Functions, and Pattern Matching. Oh My!&lt;/h2&gt;

&lt;p&gt;As a relatively new Elixir developer, I continue to be impressed by the things the language allows me to accomplish relatively easily.  Features that seemed daunting or time consuming before end up being as simple as: &amp;quot;Modules. Functions. Pattern Matching.&amp;quot; Instead of relying on pre-built solutions, a lot of the time your code ends up simpler and easier to reason about if you take advantage of what is in front of you.&lt;/p&gt;

&lt;h2&gt;Example: Web App Authorization&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s pretend we&amp;#39;re building a web application where users submit talk ideas for a conference and then the best ones are selected to be included.  Users can submit and edit their own proposals, and admins can mark a talk as &lt;code&gt;chosen&lt;/code&gt;.  We want to enforce that a rogue user can&amp;#39;t select random talks or edit other users&amp;#39; talks to be about nonsense.&lt;/p&gt;

&lt;p&gt;Not worrying about how the logic works within the application, let&amp;#39;s just lay out some rules for what users can do to talks.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule FakeConf.TalkAuthorizer do
  alias FakeConf.{Talk, User}

  # Anyone can go and create a talk
  def authorize(:create_talk, %User{} = _user), do: :ok

  # Only the user that created a talk can edit it
  def authorize(:edit_talk, %User{} = user, %Talk{} = talk) do
    if owned_by?(user, talk) do
      :ok
    else
      {:error, :unauthorized}
    end
  end

  # Only admins can &#39;choose&#39; talks
  def authorize(:choose_talk, %User{is_admin: true} = user, %Talk{}), do: :ok
  def authorize(:choose_talk, %User{}, %Talk{}), do: {:error, :unauthorized}

  defp owned_by?(%User{} = user, %Talk = talk) do
    talk.user_id == user.id
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This keeps our authorization code nice and contained!  When we implement more features, it will be easy to add them to this module.&lt;/p&gt;

&lt;p&gt;Now that we have these rules, we can use them in our application.  We&amp;#39;ll use the new &lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Kernel.SpecialForms.html#with/1&quot;&gt;with&lt;/a&gt; macro here to chain authorization into our existing app logic.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule FakeConf.Talks do
  alias FakeConf.{Talk, Repo, TalkAuthorizer}

  def create_talk(%User{} = user, talk_params) do
    talk = %Talk{user_id: user.id}
    with :ok &amp;lt;- TalkAuthorizer.authorize(:create_talk, user),
         {:ok, talk} &amp;lt;- Repo.insert(changeset(talk, talk_params)) do
      :ok
    else
      {:error, :unauthorized} -&amp;gt; {:error, :unauthorized}
    end
  end

  def edit_talk(%User{} = user, talk_id, talk_params) do
    with %Talk{} = talk &amp;lt;- Repo.get(Talk, talk_id),
         :ok &amp;lt;- TalkAuthorizer.authorize(:edit_talk, user, talk),
         {:ok, talk} &amp;lt;- Repo.update(changeset(talk, talk_params)) do
      :ok
    else
      {:error, :unauthorized} -&amp;gt; {:error, :unauthorized}
      {:error, :not_found} -&amp;gt; {:error, :not_found}
    end
  end

  def choose_talk(%User{} = user, talk_id) do
    with %Talk{} = talk &amp;lt;- Repo.get(Talk, talk_id),
         :ok &amp;lt;- TalkAuthorizer.authorize(:choose_talk, user, talk),
         {:ok, talk} &amp;lt;- Repo.insert(changeset(talk, %{chosen: true})) do
      :ok
    else
      {:error, :unauthorized} -&amp;gt; {:error, :unauthorized}
      {:error, :not_found} -&amp;gt; {:error, :not_found}
    end
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Super simple, clean, and easy to read because we&amp;#39;re combining functions that are organized in modules.  Nothing crazy happening.&lt;/p&gt;

&lt;p&gt;This isn&amp;#39;t just an example of how to do authorization. When you&amp;#39;re looking to add a feature to your application, consider it might be simpler than you think when you take advantage of the tools you have available.  When in doubt... &amp;#39;Keep It Simple, Silly&amp;#39;!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Deep Work - Lessons I will apply to UX Design</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/24/deep-work" />
    <id>https://dockyard.com/blog/2016/08/24/deep-work</id>
    
    <published>2016-08-24 00:00:00</published>
    <updated>2016-09-14 14:36:43</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>When should you schedule deep vs. shallow work for a UX design team?</summary>
    <content type="html">&lt;p&gt;Last week, I finished Kal Newportâs &lt;a href=&quot;http://calnewport.com/books/deep-work/&quot;&gt;Deep
Work&lt;/a&gt;. I started out reading the
book, but about halfway through realized Iâm getting a lot of value from
it and purchased the audiobook of it as well. This not only increased my
retention of the material, but allowed me to listen to it while doing
other things. I got through the book at least twice within three weeks,
a relatively fast pace for me.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://calnewport.com/wp-content/uploads/2015/11/deep-work-cal-newport.jpg&quot; alt=&quot;Deep Work book cover&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Deep Work&lt;/em&gt; had many takeaways for my career as a whole, but it seemed
especially useful for running design processes. A key concept in the
book is the title, Deep Work: it is both the state and the ability to
concentrate on knowledge work, and is the opposite of a distracted
state. Kal argues that deep work is becoming more important &lt;em&gt;and&lt;/em&gt; more
scarce in the current economy.&lt;/p&gt;

&lt;h2&gt;There is deep work in UX design&lt;/h2&gt;

&lt;p&gt;The first thing I considered was, which parts of my and my teamâs jobs
deep work applies to. Does my entire day need to be deep? When is the
best time to schedule âshallowâ vs. deep tasks?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;One key activity where I see the most need for deep work is &lt;strong&gt;the
Discovery phase of a project&lt;/strong&gt;. Specifically, the second half - once
weâve opened up the playing field and outlined all the possible ideas
and directions in which we could potentially focus our effort, we must
narrow down to get to a realistic product definition. Kal describes this
process as operating with many variables and considerations in our
active memory. To keep this focus, we must perform deep work.
Distraction at this point is very costly, because it requires a long
time to get re-started even after a quick break.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another key activity where I know deep work is needed is &lt;strong&gt;the
wrap-up of a project&lt;/strong&gt;. The last week of design work (letâs say weâre
talking about a 5-6 weeks total) involves making detailed changes and
refinements to designs, as well as looking at the big picture to ensure
all needs are covered. The combination of detail focus and the âbig
pictureâ in the active memory is quite taxing as it is. Even a quick
switch of focus to answer a question on another project will impact the
quality or speed of the wrap-up.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Thereâs a time &amp;amp; place for less-deep work&lt;/h2&gt;

&lt;p&gt;In planning my and my teamâs time I also need to consider activities
which can be performed in a more âshallow workâ mindset. While we could
ideally have full focus all of the time, we do need to prioritize. Here
are some things that would suffer less from a shallow focus mindset, and
potentially even benefit from a  relaxed, improvisational atmosphere,
where group chatter and distraction can actually lead to new ideas.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Every project has some component of â&lt;strong&gt;poking around&lt;/strong&gt;â or initial
research into visual style, the industry, or typical interactions of
a given type. (Do not confuse this with the deeper research and strategy
efforts, which are focused on getting very specific, hard-to-find
answers.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the &lt;strong&gt;middle of the visual design effort&lt;/strong&gt;, with tasks and
priorities lined up and activities somewhat predictable, shallow work
may be acceptable. Itâs still beneficial to keep sustained focus, but
the cost of focus switching is relatively lower.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Collaboration and critique&lt;/strong&gt; (also called design reviews) can be a
great âshallowâ activity. For example, when I check in with the team
to see how their day went, I might actually benefit from having a
shallower focus on their specific project. From this outsider
perspective, I can catch âobviousâ things they may not have noticed due
to a deeper focus on the details, but avoid micro-managing and let folks
be professionals and own their own work.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;You may already be scheduling deep work&lt;/h2&gt;

&lt;p&gt;As I looked back on the way DockYard Design operates after reading &lt;em&gt;Deep
Work&lt;/em&gt;, I noticed that weâre well on our way to creating a system that
supports deep work where needed. For example, when running design
sprints, we go âofflineâ - meaning weâre less available on Slack or by
email - for large chunks of the day. We also schedule time to catch up
on shallow tasks around those focused times: a typical in-person
collaboration would be scheduled 10ânoon and 1â4, leaving an hour of our
workday in the morning and afternoon to catch up, document and regroup
with the team.&lt;/p&gt;

&lt;p&gt;I also noticed (with no surprise) that a schedule heavily focused on
management cannot be fully tailored to maximize deep work. There will be
times when meetings, or urgent questions will take priority and the
amount of deep work I can schedule around them will be decreased.&lt;/p&gt;

&lt;h2&gt;The main takeaways&lt;/h2&gt;

&lt;p&gt;If I were to summarize the key takeaways from the book, hereâs what
youâd see:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Schedule deep and important work in large, unbroken chunks of time
first. Then, schedule shallower tasks together in batches around that.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Most people donât consider their availability purposefully. With
modern communication tools, weâve become available by default, and
it is costing us the ability to focus. If nothing else - question this
assumption, and consider the consequences of allowing yourself to be
distracted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One interesting strategy to manage shallow work is to schedule a
specific, limited portion of your work day to tackle shallow tasks.
This way, the less-important tasks may not get done, but they will also
not prevent you from achieving the truly important goals, which require
deep work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kal proposes to measure the depth of any given task by imagining how
long it would take a bright and energetic recent college graduate to
train up to do the task for you. If the time is relatively short (e.g.
taking a couple of weeks to learn how to manage a social media presence)
then the task is shallow. If the time is long (e.g. taking several years
to learn how to create original academic research or acquire insight to
write a book) then the task is deep.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In conclusion - &lt;em&gt;Deep Work&lt;/em&gt; questions many assumptions about the way we
run our work lives, and proposes specific alternatives. The book is
structured as such a clear logical argument (perhaps, owing to Kalâs
background in the theory of computation and his academic writing) that
itâs hard to ignore the advice. It felt a bit repetitive as I was
listening to the introductory chapter (in a Dale Carnegie kind of way)
but Iâm now reaping the benefit of that repetition by being able to
recite the argument back to anyone whoâd care to listen. This is great
book for any knowledge worker, and Iâve confirmed that itâs useful for
anyone in a design role. I highly recommend it!&lt;/p&gt;
</content>
  </entry><entry>
    <title>What design discovery feels like</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/23/what-design-discovery-feels-like" />
    <id>https://dockyard.com/blog/2016/08/23/what-design-discovery-feels-like</id>
    
    <published>2016-08-23 00:00:00</published>
    <updated>2016-09-14 14:36:43</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Sometimes your job is to do the figuring-out so others can start building and designing the actual thing.</summary>
    <content type="html">&lt;p&gt;I often struggle to describe what it is that I do for a living. You may
feel the same, especially when talking to friends outside of your
industry, or at any given family gathering. In the past few months, a
large and I believe most important part of my job at DockYard was
helping get projects started right.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/xQ3DXsy.jpg&quot; alt=&quot;designer at work&quot;&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A stereotypical UX designer at work. Sticky notes in bright colors are essential.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We call this initial phase of a project design discovery, and believe
that a design-first approach saves a lot of money and frustration by
figuring everything out with the simplest paper-and-pen prototypes
first. But Iâm not talking about the business logic, or methods that
inform discovery right now. I want to talk about how it feels to be part
of it - from the beginning, staring at a bunch of unknowns, and right
through the end when the answer becomes clear.&lt;/p&gt;

&lt;p&gt;Among all the things I do, the activity of kicking off projects is the
hardest one to describe. Itâs the thing that needs to happen before
anyone can start making the &lt;em&gt;actual&lt;/em&gt; thing. Before youâve done a
discovery, you mostly have questions, or rather, you have questions
about what the questions should be. (After all, asking the correct
question is 80% of solving a problem.) Then, as you work through user
flows and specific screens the answers start to become more obvious, and
you can make decisions together with the client about what the thing
youâre building should do, and which features youâll build first to make
that possible.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/4A8ahwJ.jpg&quot; alt=&quot;paper and pen prototypes&quot;&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Feeling âdoneâ with discovering something doesnât always look complex.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If all goes well, the end result should look suspiciously simple.
Obvious, even. Youâll have gotten rid of many creative but complex
features. Those would be nice to have in the future,  but it doesnât
make sense to invest in the bells and whistles until youâve built the
basics. The outcome of a Discovery can feel like the outcome of a good
summer vacation. Youâve done some (but not all) of all the possible
things youâd imagined youâd do. Youâve had to narrow down your long list
of fuzzy imagined dream-like things you could possibly do to a realistic
and actionable schedule.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/oDu1uJ3.gif&quot; alt=&quot;river grass underwater&quot;&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The feeling of summer and possibility is similar to the beginning of
discovery. It wonât last forever, but enjoy it while it does!
&lt;a href=&quot;http://www.designartpractice.com/blog/38&quot;&gt;Image Credit&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Discovery is a process that turns a strong desire to have a vacation,
plus a list of ideas and dreams into something you can reliably act
upon. If the end of summer has ever hit you by surprise, as you realized
youâd never made time for the one important trip youâd definitely
thought youâd do this year - planning could help.&lt;/p&gt;

&lt;p&gt;And if youâre an entrepreneur, or a UX designer, or even an engineer
about to embark on a discovery process, this is how it should feel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And in the beginning&lt;/strong&gt;, itâs open and exciting but often so open itâs
scary. Your collaborators keep asking seemingly obvious questions.  (We
uncover a new and important motivation every single time. Itâs worth the
time and effort.) It can be frustrating because the things you thought
were clear still need definition. Things can even get heated, as you
discuss the details of a collaborative project and realize your
assumptions might be different from your collaboratorsâ, and also
different from the assumptions your users hold. The early stages of a
discovery are like the beginning, dreamy stages of planning a vacation.
You know a good thing is ahead, and you can spend some time with all the
possible amazing options open to you, but know that the longer you delay
the decisions, the longer you wait to do the actual thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the middle&lt;/strong&gt;, itâs hard. Youâre making tough decisions to
prioritize among ideas and features, while you care and see the need for
all of them. (Eventually).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At the end&lt;/strong&gt;, things look obvious - so obvious that you canât wait to
get started actually making them. You know exactly what to do first.&lt;/p&gt;

&lt;p&gt;Enjoy the rest of the summer! (Remember, officially, we have till
September 21st :-)&lt;/p&gt;
</content>
  </entry><entry>
    <title>The minimum knowledge you need to start Metaprogramming in Elixir</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/16/The-minumum-knowledge-you-need-to-start-metaprogramming-in-Elixir" />
    <id>https://dockyard.com/blog/2016/08/16/The-minumum-knowledge-you-need-to-start-metaprogramming-in-Elixir</id>
    
    <published>2016-08-16 00:00:00</published>
    <updated>2016-08-27 10:02:01</updated>
    <author><name>Daniel Xu</name></author>
    <summary>Metaprogramming Elixir</summary>
    <content type="html">&lt;p&gt;Metaprogramming is &lt;code&gt;writing code that writes code&lt;/code&gt;. In Elixir, we use macros to transform our internal program structure (AST) in compile time to something else. For example, the &lt;code&gt;if&lt;/code&gt; macro is transformed to &lt;code&gt;case&lt;/code&gt; during compilation, we call this &lt;code&gt;macro expansion&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;if true do
  IO.puts &amp;quot;yea&amp;quot;
end

# becomes

case(true) do
  x when x in [false, nil] -&amp;gt;
    nil
  _ -&amp;gt;
    IO.puts(&amp;quot;yea&amp;quot;)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;The Abstract Syntax Tree (AST) and AST literal&lt;/h2&gt;

&lt;p&gt;The internal representation of Elixir code is an &lt;a href=&quot;https://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;abstract syntax tree&lt;/a&gt; which is the protagonist in program transformation. Elixir also refers to an AST as a &lt;code&gt;quoted expression&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The quoted expression is composed of three-element tuples:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# simple one: AST for 1 + 2
{:+, [context: Elixir, import: Kernel], [1, 2]}

# nested one:
# AST for
# def hello do
#   IO.puts &amp;quot;hello&amp;quot;
# end

{:def, [context: Elixir, import: Kernel],
 [{:hello, [context: Elixir],
   [[do: {{:., [], [{:__aliases__, [alias: false], [:IO]}, :puts]}, [],
      [&amp;quot;hello&amp;quot;]}]]}]}

&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Essentially, All tuples in the AST follow the same pattern:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{function_call, meta_data_for_context, argument_list}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;During compilation, all of our source code will be &lt;strong&gt;transformed into AST&lt;/strong&gt; before producing final bytecode. However, there are &lt;strong&gt;five&lt;/strong&gt; Elixir literals that will remain the same format as their high-level source.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Pl3zRn8.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;The following example shows the differences between Elixir literal and other normal data types:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# AST for {1, 2, 3}
{:{}, [], [1, 2, 3]}

# AST for %{a: :hello}
{:%{}, [], [a: :hello]}

# AST for {1, 2} (AST literal)
{1, 2}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Macro&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Macros receive AST as arguments and provide AST as return values&lt;/strong&gt;. The returned AST is injected back into the global programâs compile tree, in this way, macros enable syntactic extensions and code generation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Syntactic extensions: e.g. we can implement &lt;code&gt;while&lt;/code&gt; which is not available in Elixir or create DSL&lt;/li&gt;
&lt;li&gt;Code generation: e.g. generate function from external data&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Return AST&lt;/h3&gt;

&lt;p&gt;There are three ways to create quoted expressions in Elixir:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manually construct it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Macro.escape&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;quote&lt;/code&gt;/&lt;code&gt;unquote&lt;/code&gt; to compose AST&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule MyMacro do
  @opts: %{time: :am}

  # case 1
  defmacro one_plus_two do
    {:+, [], [1, 2]}
  end

  # case 2
  defmacro say_hi do
    quote do
      IO.puts &amp;quot;hello world&amp;quot;
    end
  end

  # case 3
  defmacro ops do
    Macro.escape(@opts)
  end
end

defmodule MyModule do
  import Mymacro

  def case1 do
    IO.puts one_plus_two()
  end

  def case2 do
    say_hi()
  end

  def case3 do
    IO.inspect ops()
  end
end

#=&amp;gt; c &amp;quot;example.exs&amp;quot;
#=&amp;gt; MyModule.case1()
#=&amp;gt; &amp;quot;3&amp;quot;
#=&amp;gt; MyModule.case2()
#=&amp;gt; &amp;quot;hello world&amp;quot;
#=&amp;gt; MyModule.case3()
#=&amp;gt; %{time: :am}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this example, we define three macros using &lt;code&gt;defmacro&lt;/code&gt;, all of them return quoted expressions, then we import &lt;code&gt;MyMacro&lt;/code&gt; module into &lt;code&gt;MyModule&lt;/code&gt;. During compilation, these macros will be expanded and the returned AST will be injected into &lt;code&gt;MyModule&amp;#39;s&lt;/code&gt; compile tree.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s difficult to construct an AST by hand. We should almost always should use &lt;code&gt;quote&lt;/code&gt; and &lt;code&gt;Macro.escape&lt;/code&gt; to build up an AST using Elixir&amp;#39;s own syntax. The main differences between these two are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;quote&lt;/code&gt; returns AST of passed in code block.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Macro.escape&lt;/code&gt; returns AST of passed in value.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some examples:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;data = {1, 2, 3}

quote do: {1, 2, 3}
#=&amp;gt; {:{}, [], [1, 2, 3]} (AST of {1, 2, 3})

quote do: data
#=&amp;gt; {:data, [], Elixir} (data is not inject into returned AST)

quote do: IO.inspect(1)
#=&amp;gt; {{:., [], [{:__aliases__, [alias: false], [:IO]}, :inspect]}, [], [1]}
quote do: IO.inspect(data)
#=&amp;gt;{{:., [], [{:__aliases__, [alias: false], [:IO]}, :inspect]}, [],
 [{:data, [], Elixir}]}

Macro.escape(data)
#=&amp;gt; {:{}, [], [1, 2, 3]}

IO.inspect(1)
|&amp;gt; Macro.escape()
#=&amp;gt; :error
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice that &lt;code&gt;data&lt;/code&gt; variable is not injected into the AST returned by &lt;code&gt;quote&lt;/code&gt; block, in order to do that, we need to use &lt;code&gt;unquote&lt;/code&gt;, which we will discuss later.&lt;/p&gt;

&lt;h3&gt;Receive AST&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s take an example to see how macros receive AST:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule M do
  defmacro macro_args(a, b) do
    IO.inspect a
    IO.inspect b
  end
end

#=&amp;gt; c &amp;quot;example.exs&amp;quot;
{:+, [line: 22], [1, 1]}
2
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After compiling the module, we can see the results: &lt;code&gt;{{:+, [line: 22], [1, 1]}}&lt;/code&gt; and &lt;code&gt;2&lt;/code&gt;, they are both quoted expressions. Remember that number is an AST literal so its quoted expressions remains the same as itself.&lt;/p&gt;

&lt;p&gt;Combining this fact with the pattern of AST, we can easily do pattern matching to get what we want from the argument for further AST composition.&lt;/p&gt;

&lt;p&gt;Keep in mind that code passed into a macro is not evaluated or executed. As we saw earlier, &lt;strong&gt;Macros receive AST as arguments and provide AST as return values&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;unquote&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;unquote&lt;/code&gt; injects quoted expressions into the AST returned by &lt;code&gt;quote&lt;/code&gt;. &lt;strong&gt;You can only use &lt;code&gt;unquote&lt;/code&gt; inside &lt;code&gt;quote blocks&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To make it easier to understand, you can think &lt;strong&gt;quote/unquote&lt;/strong&gt; as &lt;strong&gt;string interpolation&lt;/strong&gt;. When you do &lt;code&gt;quote&lt;/code&gt;, it&amp;#39;s like creating string using &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;. When you do &lt;code&gt;unquote&lt;/code&gt;, it&amp;#39;s like injecting value into string by &lt;code&gt;&amp;quot;#{}&amp;quot;&lt;/code&gt;. However, instead of manipulating string, we are composing AST.&lt;/p&gt;

&lt;p&gt;There are two types of unquote:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Normal unquote&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;data = {1, 2, 3}
quote do
  IO.inspect(unquote(data))
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It looks correct, but when we evaluate the AST, we will get an error:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/M7fHcmu.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;How come? It&amp;#39;s because we forget an important concept:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;unquote injects AST into AST returned by quote.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;{1, 2, 3}&lt;/code&gt; is not an AST literal, so we need to get the quoted expressions. first by using &lt;code&gt;Macro.escape&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;data = {1, 2, 3}
quote do
  IO.inspect(unquote(Macro.escape(data)))
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Unquote fragment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unquote fragment is added to support &lt;strong&gt;dynamic generation of functions&lt;/strong&gt; and &lt;strong&gt;nested macros&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule MyModule do
  Enum.each [foo: 1, bar: 2, baz: 3], fn { k, v } -&amp;gt;
    def unquote(k)(arg) do
      unquote(v) + arg
    end
  end
end

#=&amp;gt; MyModule.foo(1) #2
#=&amp;gt; MyModule.bar(1) #3
#=&amp;gt; MyModule.baz(2) #4
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this example, we use &lt;code&gt;unquote(k)&lt;/code&gt; as function name to generate functions from keys of a Keyworld list.&lt;/p&gt;

&lt;p&gt;You might wonder why we can use &lt;code&gt;unquote&lt;/code&gt; without &lt;code&gt;quote&lt;/code&gt;. It&amp;#39;s because &lt;code&gt;def&lt;/code&gt; is macro, its arguments will be quoted automatically as we discussed above.&lt;/p&gt;

&lt;p&gt;Besides, we need &lt;code&gt;quote(v)&lt;/code&gt; inside function body because of scope rule in Elixir:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;for named function, any variable coming from the surrounding scope has to be unquoted inside a function clause body.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Bind_quoted&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;bind_quoted&lt;/code&gt; does two things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; prevent accidental reevaluation of bindings.&lt;/p&gt;

&lt;p&gt;If we have two same &lt;code&gt;unquote&lt;/code&gt; inside &lt;code&gt;quote&lt;/code&gt; block, the &lt;code&gt;unquote&lt;/code&gt; will be evaluated twice, this can cause problem.
We can use &lt;code&gt;bind_quoted&lt;/code&gt; to fix it:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# bad
defmacro my_macro(x) do
  quote do
     IO.inspect unquote(x) * unquote(x)
  end
end

# good
defmacro my_macro(x) do
  quote bind_quoted: [x: x] do
     IO.inspect x * x
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; Defer the execution of &lt;code&gt;unquote&lt;/code&gt; via &lt;code&gt;unquote: false&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;unquote: false&lt;/code&gt; is the default behavior of &lt;code&gt;bind_quoted&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;order of execution&lt;/strong&gt; is:&lt;/p&gt;

&lt;p&gt;when a macro module is compiled, code in the macro context will run first (&lt;code&gt;IO.puts 1&lt;/code&gt;). Normal code in &lt;code&gt;quote&lt;/code&gt; block will not be executed until the returned AST is injected into caller module. However, &lt;code&gt;unquote&lt;/code&gt; code will &amp;quot;break the wall&amp;quot; and run in macro&amp;#39;s context.&lt;/p&gt;

&lt;p&gt;Macro module&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule M do
  defmacro my_macro(name) do
    # macro context
    IO.puts 1

    quote do
      # caller context
      IO.puts 4
      unquote(IO.puts 2)
    end
  end
end

&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Caller Module&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule Create do
  import M
  IO.puts 3
  my_macro(&amp;quot;hello&amp;quot;)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;According to the explanation above, we can know the result of the example is: &lt;code&gt;1 2 3 4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we use &lt;code&gt;bind_quoted&lt;/code&gt; in the example, the order will change. The &lt;code&gt;unquote&lt;/code&gt; code will be treated as normal code and run in caller&amp;#39;s context. Therefore, the result for the following example is: &lt;code&gt;1 3 4 2&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule M do
  defmacro my_macro(name) do
    IO.puts 1

    quote bind_quoted: [name: name] do
      IO.puts 4

      def unquote(name)() do
        unquote(IO.puts 2)
        IO.puts &amp;quot;hello #{unquote(name)}&amp;quot;
      end
    end
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule Create do
  import M
  IO.puts 3
  my_macro(:hello)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is helpful because when we change &lt;code&gt;my_macro(:hello)&lt;/code&gt; in caller module  to&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;  [:foo, :bar]
  |&amp;gt; Enum.each(&amp;amp;my_macro(&amp;amp;1))
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Our code will still work because the &lt;code&gt;each&lt;/code&gt; function is executed before the injected AST.&lt;/p&gt;

&lt;h2&gt;How to do experiments&lt;/h2&gt;

&lt;p&gt;The best way to learn is trial and error. Elixir provides a few functions that can help us: &lt;code&gt;IO.inspect&lt;/code&gt;, &lt;code&gt;Code.eval_quoted&lt;/code&gt;, &lt;code&gt;Macro.to_string&lt;/code&gt;, and &lt;code&gt;Macro.expand/Macro.expand_once&lt;/code&gt;. Let&amp;#39;s find out more about each one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IO.inspect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can use &lt;code&gt;IO.inspect&lt;/code&gt; to output the details of macro arguments or whatever we want.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code.eval_quoted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;eval_quoted&lt;/code&gt; helps to evalute AST we created:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;data = {1, 2, 3}
ast = quote do
  IO.inspect(unquote(Macro.escape(data)))
end
Code.eval_quoted(ast)

#=&amp;gt; {1, 2, 3}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Macro.to_string&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It converts the given quoted expressions to a string.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Macro.to_string(ast)
#=&amp;gt; &amp;quot;IO.inspect({1, 2, 3})&amp;quot;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Macro.expand/Macro.expand_once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Macro.expand&lt;/code&gt; will receive an AST node and recursively expand it.
We can also expand AST once a time using &lt;code&gt;Macro.expand_once&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ast = quote do: if true, do: IO.puts 1
Macro.expand_once(ast, __ENV__)

{:case, [optimize_boolean: true],
     [true,
      [do: [{:-&amp;gt;, [],
         [[{:when, [],
            [{:x, [counter: 0], Kernel},
             {:in, [context: Kernel, import: Kernel],
              [{:x, [counter: 0], Kernel}, [false, nil]]}]}], nil]},
        {:-&amp;gt;, [],
         [[{:_, [], Kernel}],
          {{:., [], [{:__aliases__, [alias: false, counter: 0], [:IO]}, :puts]}, [],
           [1]}]}]]]}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Resources&lt;/h2&gt;

&lt;p&gt;Now we know the basic about metaprogramming in Elixir, it&amp;#39;s time to write simple macro, do some experiments and read source code of Elixir or Phoenix.&lt;/p&gt;

&lt;p&gt;Also, there are two great resouces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pragprog.com/book/cmelixir/metaprogramming-elixir&quot;&gt;Metaprogramming Elixir&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/chris_mccord&quot;&gt;ChrisMcCord&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Great book to read. A lot of practical examples in the book that teach you how to write macros.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://theerlangelist.com/article/macros_1&quot;&gt;understanding macro blog series&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/sasajuric&quot;&gt;SaÅ¡a JuriÄ
&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry><entry>
    <title>Pieces of Ember: Part 1</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/12/pieces-of-ember-part1" />
    <id>https://dockyard.com/blog/2016/08/12/pieces-of-ember-part1</id>
    
    <published>2016-08-12 00:00:00</published>
    <updated>2016-09-14 14:36:43</updated>
    <author><name>Heather Brysiewicz</name></author>
    <summary>How to leverage the Ember ecosystem without the Ember ecosystem</summary>
    <content type="html">&lt;p&gt;I&amp;#39;ve been working with &lt;a href=&quot;//emberjs.com&quot;&gt;Ember&lt;/a&gt; for years now, even though it feels like just yesterday. Not everyone has had this opportunity and I am often met with questions from inquisitive developers and engineers about the state of Ember.&lt;/p&gt;

&lt;p&gt;They know that Ember is an ambitious framework. They&amp;#39;ve heard it can help boost their productivity. Yet, they hesitate. The project put in their hands is &amp;quot;basically just a landing page&amp;quot; or they believe most frameworks to be excessive - and this concern can be valid. Ember is a mature framework with opinions, build tools, and blueprints that enable me, an Ember developer, to focus on engineering an application rather than boilerplate and redundancy.&lt;/p&gt;

&lt;p&gt;What these developers probably don&amp;#39;t know is that many of the core pieces that make the Ember ecosystem the beautiful powerhouse that it is are also available as micro-libraries.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;
  &lt;img src=&quot;https://i.imgur.com/PfqFoEW.png&quot;&gt;
&lt;/div&gt;
&lt;br&gt;&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Some of the most well known micro-libraries behind the Ember framework are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;//github.com/tildeio/rsvp.js&quot;&gt;tildeio/rsvp.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;//github.com/broccolijs/broccoli&quot;&gt;broccolijs/broccoli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;//github.com/tildeio/route-recognizer&quot;&gt;tildeio/route-recognizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;//github.com/tildeio/router.js&quot;&gt;tildeio/router.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;//github.com/wycats/handlebars.js&quot;&gt;wycats/handlebars.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;//github.com/tildeio/htmlbars&quot;&gt;tildeio/htmlbars&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These pieces of Ember would be able to provide any JavaScript project with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Promises&lt;/li&gt;
&lt;li&gt;Build tools&lt;/li&gt;
&lt;li&gt;Routing capabilities&lt;/li&gt;
&lt;li&gt;View templating&lt;/li&gt;
&lt;li&gt;Templating with Virtual DOM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All without the need to buy into the entire Ember ecosystem.&lt;/p&gt;

&lt;p&gt;This post is part 1 of a 3 part series on the pieces of Ember. It is also a continuation or elaboration of a lightning talk I gave at the July &lt;a href=&quot;//sandiegojs.org&quot;&gt;SanDiego.js Community&lt;/a&gt; event which can be found &lt;a href=&quot;https://youtu.be/wb-24NqCOT0?t=33m34s&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;//dockyard.com/blog/2016/08/12/pieces-of-ember-part1&quot;&gt;Part 1: RSVP and Broccoli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part 2: Route-recognizer and Router&lt;/li&gt;
&lt;li&gt;Part 3: Handlebars and HTMLBars&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;&lt;a href=&quot;//github.com/tildeio/rsvp.js&quot;&gt;tildeio/rsvp.js&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;This library is a tiny implementation of the &lt;a href=&quot;https://promisesaplus.com/&quot;&gt;Promises/A+ spec&lt;/a&gt;. This can be used without a transpiler just like any other promise library.&lt;/p&gt;

&lt;p&gt;The library itself is rather similar to &lt;a href=&quot;http://bluebirdjs.com/&quot;&gt;Bluebird&lt;/a&gt; and &lt;a href=&quot;https://github.com/cujojs/when&quot;&gt;When&lt;/a&gt;. Under the hood there are some performance boosts gained by avoiding unnecessary internal promise allocations. This provides noticeable improvements in many common scenarios.&lt;/p&gt;

&lt;p&gt;The other unique thing to note about this library is that RSVP aims to be fast across more than just the V8 runtime, while libraries like Bluebird are more or less V8-focused.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let RSVP = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;rsvp&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

let promise = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; RSVP.Promise((resolve, reject) =&amp;gt; {
  &lt;span class=&quot;comment&quot;&gt;//succeed&lt;/span&gt;
  resolve(value);
  &lt;span class=&quot;comment&quot;&gt;// or reject&lt;/span&gt;
  reject(error)
});

promise.then((value) =&amp;gt; {
  &lt;span class=&quot;comment&quot;&gt;//success&lt;/span&gt;
}).&lt;span class=&quot;keyword&quot;&gt;catch&lt;/span&gt;((error) =&amp;gt; {
  &lt;span class=&quot;comment&quot;&gt;// failure&lt;/span&gt;
});

&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;&lt;a href=&quot;//github.com/broccolijs/broccoli&quot;&gt;broccolijs/broccoli&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Broccoli is the fast build pipeline used by &lt;a href=&quot;https://ember-cli.com&quot;&gt;ember-cli&lt;/a&gt; and that is available outside of the Ember ecosystem. Broccoli is intended to be relatively easy to learn, performant, and composable. The plugin system for broccoli is what makes it so composable and even with plugins depending on other plugins, creating a large tree of plugin dependencies, broccoli manages to still provide performant sub-second speeds.&lt;/p&gt;

&lt;p&gt;Broccoli provides a powerful build tool chain that can be used very easily to get a project up and running outside of Ember.&lt;/p&gt;

&lt;p&gt;Given a simple project with the following structure:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;.
+-- app
|   +-- css
|   +-- js
|   +-- img
|   +-- index.html
+-- node_modules/
+-- .gitignore
+-- Brocfile.js
+-- README.md
+-- package.json
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It is easy to serve up the assets and create a pipeline with just a few key broccoli plugins and a rather short &lt;code&gt;Brocfile.js&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ npm i --save-dev broccoli-concat
$ npm i --save-dev broccoli-merge-trees
$ npm i --save-dev broccoli-static-compiler
$ npm i --save-dev broccoli-uglify-js
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
52
53
54
55
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;use strict&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const concatenate = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-concat&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
const mergeTrees = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-merge-trees&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
const pickFiles = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-static-compiler&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
const uglifyJS = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-uglify-js&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

const app = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

let appCSS;
let appHTML;
let appJS;
let appImages;

&lt;span class=&quot;comment&quot;&gt;/*
 * move index from `app/` to root of tree
 */&lt;/span&gt;
appHTML = pickFiles(app, {
    &lt;span class=&quot;key&quot;&gt;srcDir&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;key&quot;&gt;files&lt;/span&gt;: [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;],
    &lt;span class=&quot;key&quot;&gt;destDir&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

&lt;span class=&quot;comment&quot;&gt;/*
 * concat and compress all js files from `app/js/` and move to root
 */&lt;/span&gt;
appJS = concatenate(app, {
  &lt;span class=&quot;key&quot;&gt;inputFiles&lt;/span&gt;: [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;js/**/*.js&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;],
  &lt;span class=&quot;key&quot;&gt;outputFile&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/app.js&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

appJS = uglifyJS(appJS, {
  &lt;span class=&quot;key&quot;&gt;compress&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
});

&lt;span class=&quot;comment&quot;&gt;/*
 * concat all css files from `app/css/` and move to root
 */&lt;/span&gt;
appCSS = concatenate(app, {
  &lt;span class=&quot;key&quot;&gt;inputFiles&lt;/span&gt;: [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;css/**/*.css&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;],
  &lt;span class=&quot;key&quot;&gt;outputFile&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/app.css&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

&lt;span class=&quot;comment&quot;&gt;/*
 * move images from `app/img` to image folder
 */&lt;/span&gt;
appImages = pickFiles(app, {
  &lt;span class=&quot;key&quot;&gt;srcDir&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/img&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;files&lt;/span&gt;: [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;**/*&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;],
  &lt;span class=&quot;key&quot;&gt;destDir&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/img&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

&lt;span class=&quot;comment&quot;&gt;// merge the trees and export&lt;/span&gt;
module.exports = mergeTrees([appHTML, appJS, appCSS, appImages]);

&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now running &lt;code&gt;broccoli serve&lt;/code&gt; will build and serve the project and provide build times in a well formated and easy to read table.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Serving on http://localhost:4200


Slowest Trees                                 | Total
----------------------------------------------+---------------------
SourceMapConcat                               | 30ms
UglifyJSFilter                                | 13ms
BroccoliMergeTrees                            | 7ms
StaticCompiler                                | 3ms
Slowest Trees (cumulative)                    | Total (avg)
----------------------------------------------+---------------------
SourceMapConcat (1)                           | 30ms
UglifyJSFilter (1)                            | 13ms
BroccoliMergeTrees (1)                        | 7ms
StaticCompiler (2)                            | 6ms (3 ms)

Built - 63 ms @ Tue Jul 26 2016 16:43:40 GMT-0700 (PDT)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When ready to build for deployment the command &lt;code&gt;broccoli build &amp;#39;dist&amp;#39;&lt;/code&gt; would compile all of the assets into the &lt;code&gt;dist&lt;/code&gt; directory.&lt;/p&gt;

&lt;h3&gt;Get more from the Ember ecosystem&lt;/h3&gt;

&lt;p&gt;Check back for part 2 and part 3 of this series where I review the routing capabilities and templating systems and how to use them outside of Ember.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Using Ecto Changesets for HTML input validations</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/11/changeset-form-validation-bindings" />
    <id>https://dockyard.com/blog/2016/08/11/changeset-form-validation-bindings</id>
    
    <published>2016-08-11 00:00:00</published>
    <updated>2016-08-27 10:02:01</updated>
    <author><name>Nico Mihalich</name></author>
    <summary>Leverage the power of Phoenix to utilize your Ecto changeset validations as input validations in your HTML forms</summary>
    <content type="html">&lt;p&gt;All web applications with user submitted input have some constraints on what input is acceptable.  We as developers have two methods to make sure what the user entered falls within those constraints.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Client Side Validation&lt;/em&gt; where your application checks form data prior to a network call and prevents the call from happening if it finds the data invalid.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Server Side Validation&lt;/em&gt; where your application sends data to the server and waits for it to tell you if the data is valid or not.&lt;/p&gt;

&lt;p&gt;Both are means to the same end but have their advantages and disadvantages.&lt;/p&gt;

&lt;h2&gt;Server Side Validation (Necessary)&lt;/h2&gt;

&lt;h3&gt;Pros&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Source of truth / &amp;quot;Last line of defense&amp;quot;&lt;/li&gt;
&lt;li&gt;Can be tied to DB logic&lt;/li&gt;
&lt;li&gt;Knows context of the user, session, or other data&lt;/li&gt;
&lt;li&gt;More powerful and secure&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Cons&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Slow to get feedback due to network latency&lt;/li&gt;
&lt;li&gt;Sending the entire form just to get one error&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Client Side Validations (Optional)&lt;/h2&gt;

&lt;h3&gt;Pros&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Immediate validation&lt;/li&gt;
&lt;li&gt;Preventative&lt;/li&gt;
&lt;li&gt;Semantically accurate&lt;/li&gt;
&lt;li&gt;Nicer feeling feedback due to styling with CSS selectors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Cons&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Have to keep it in sync with server side&lt;/li&gt;
&lt;li&gt;Brittle&lt;/li&gt;
&lt;li&gt;Not a substitute for server side validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generally client side validations are optional, faster, and provide better UX, while server side validations are necessary, stronger, and better tied to your data schema.&lt;/p&gt;

&lt;p&gt;Ideally you utilize both, but they&amp;#39;re a pain to keep in sync.  In a perfect world your application&amp;#39;s back end validations automatically apply to the client. We&amp;#39;re going to explore how Phoenix and Ecto give us the power to help us do exactly that.&lt;/p&gt;

&lt;p&gt;We can leverage &lt;a href=&quot;http://www.phoenixframework.org/&quot;&gt;Phoenix&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html&quot;&gt;Ecto.Changeset&lt;/a&gt; on our front end with just a few lines of code. This doesn&amp;#39;t work for everything (uniqueness constraints for example), but there are some nice things we can validate for: min/max, length, and required fields.
Ecto changesets within Phoenix support &lt;a href=&quot;https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/html.ex#L143&quot;&gt;validate_length&lt;/a&gt;, &lt;a href=&quot;https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/html.ex#L161&quot;&gt;validate_number&lt;/a&gt;, &lt;a href=&quot;https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/html.ex#L114&quot;&gt;validate_required&lt;/a&gt; which correspond to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Data_form_validation&quot;&gt;HTML input validations&lt;/a&gt; &lt;code&gt;minlength&lt;/code&gt;/&lt;code&gt;maxlength&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;/&lt;code&gt;max&lt;/code&gt;, and &lt;code&gt;required&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our goal is to have the validations defined in a schema&amp;#39;s changeset function automatically apply the correct HTML input validation to our form.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s write some code.&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;The Code&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s work with a schema named &lt;code&gt;foo&lt;/code&gt; with the following changeset function:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def changeset(struct, params \\ %{}) do
  struct
  |&amp;gt; cast(params, [:name])
  |&amp;gt; validate_required([:name])
  |&amp;gt; validate_length(:name, min: 2, max: 4)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;By default our form should have something like this:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;%= text_input f, :name, class: &amp;quot;form-control&amp;quot; %&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Which generates this markup:&lt;/p&gt;
&lt;div class=&quot;highlight html &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;form-control&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo[name]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It works, but we have to wait for a server round trip to get any validations. We can add client side validation by appending opts by hand like this:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;%= text_input f, :name, class: &amp;quot;form-control&amp;quot;, required: true, minlength: 2, maxlength: 4 %&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Which generates this markup:&lt;/p&gt;
&lt;div class=&quot;highlight html &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;form-control&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;maxlength&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;minlength&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo[name]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;required&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is better, but if we ever changed the max to something else we would have to remember to change it in two different places!&lt;/p&gt;

&lt;p&gt;We can do better by using &lt;a href=&quot;https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/html.ex#L113&quot;&gt;input_validations&lt;/a&gt;. This function generates the HTML validation attributes from our Ecto changeset for us.&lt;/p&gt;

&lt;p&gt;Now we can define our own functions which simply add on those generated input validations to our text and number inputs...&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;alias Phoenix.HTML.Form

def text_input(form, field, opts \\ []) do
  Form.text_input(form, field, opts ++ Form.input_validations(form, field))
end

def number_input(form, field, opts \\ []) do
  Form.number_input(form, field, opts ++ Form.input_validations(form, field))
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Keep the same markup we had initially...&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;%= text_input f, :name, class: &amp;quot;form-control&amp;quot; %&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;... and get the semantically correct markup with no changes to the template!&lt;/p&gt;
&lt;div class=&quot;highlight html &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;form-control&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;maxlength&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;minlength&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo[name]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;required&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Other validations&lt;/h2&gt;

&lt;p&gt;This will also work for number validations.  Say our changeset function had a line like&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;|&amp;gt; validate_number(:count, greater_than: 2, less_than: 9)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That would give us this markup&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;input class=&amp;quot;form-control&amp;quot; id=&amp;quot;foo_count&amp;quot; max=&amp;quot;8&amp;quot; min=&amp;quot;3&amp;quot; name=&amp;quot;foo[count]&amp;quot; required=&amp;quot;required&amp;quot; step=&amp;quot;1&amp;quot; type=&amp;quot;number&amp;quot;&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;hr&gt;

&lt;h2&gt;Using this in your application&lt;/h2&gt;

&lt;p&gt;To leverage this in your own Phoenix application, we&amp;#39;ll use a module that we will automatically import in all our views.&lt;/p&gt;

&lt;p&gt;First define the module with our custom &lt;code&gt;text_input&lt;/code&gt; and &lt;code&gt;number_input&lt;/code&gt; functions in &lt;code&gt;web/views/valid_inputs.ex&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule HelloPhoenix.ValidInputs do
  alias Phoenix.HTML.Form

  def text_input(form, field, opts \\ []) do
    Form.text_input(form, field, opts ++ Form.input_validations(form, field))
  end

  def number_input(form, field, opts \\ []) do
    Form.number_input(form, field, opts ++ Form.input_validations(form, field))
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then in &lt;code&gt;web/web.ex&lt;/code&gt; just have Phoenix make it available for all our views.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def view do
  quote do
    use Phoenix.View, root: &amp;quot;web/templates&amp;quot;

    # Import convenience functions from controllers
    import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1]

    # Use all HTML functionality (forms, tags, etc)
    use Phoenix.HTML

    # vvvv BEGIN OUR CODE vvvv
    import Phoenix.HTML.Form, except: [number_input: 2, number_input: 3, text_input: 3]
    import HelloPhoenix.ValidInputs
    # ^^^^ END OUR CODE ^^^^

    import HelloPhoenix.Router.Helpers
    import HelloPhoenix.ErrorHelpers
    import HelloPhoenix.Gettext
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And we&amp;#39;re done! Now that your inputs have constraints, you can use CSS selectors like &lt;code&gt;:invalid&lt;/code&gt; and &lt;code&gt;:required&lt;/code&gt; to make things look a bit nicer for the user.&lt;/p&gt;

&lt;h2&gt;Custom Validations&lt;/h2&gt;

&lt;p&gt;There&amp;#39;s also a lesser known &lt;code&gt;pattern&lt;/code&gt; HTML attribute for regex validations.  The JavaScript and Elixir regex engines are not 100% compatible so it&amp;#39;s not supported by default in &lt;code&gt;input_validations&lt;/code&gt; but we can add it ourselves as an exercise in custom validations.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;|&amp;gt; validate_format(:email, ~r/.+@.+/)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def text_input(form, field, opts \\ []) do
  Form.text_input(form, field, extend_opts(form, field, opts))
end

defp extend_opts(form, field, opts) do
  defaults = opts ++ Form.input_validations(form, field)

  case form.source.validations[field] do
    {:format, regex} -&amp;gt; [{:pattern, Regex.source(regex)} | defaults]
    _ -&amp;gt; defaults
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;input class=&amp;quot;form-control&amp;quot; id=&amp;quot;foo_email&amp;quot; name=&amp;quot;foo[email]&amp;quot; pattern=&amp;quot;.+@.+&amp;quot; type=&amp;quot;text&amp;quot;&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Because we&amp;#39;re just composing and calling functions, we can extend our initial implementation easily without having to inherit or monkey patch from an existing View module. Going further, you can tweak your &lt;code&gt;text_input&lt;/code&gt; and &lt;code&gt;number_input&lt;/code&gt; to, for example, take an optional &lt;code&gt;validate&lt;/code&gt; parameter to include opt in/opt out functionality.&lt;/p&gt;

&lt;h2&gt;The takeaway&lt;/h2&gt;

&lt;p&gt;Using simple functions available in Phoenix, your application can automatically apply some of your in-place server side validations to your front end markup to improve your UX in only a few lines of code!&lt;/p&gt;
</content>
  </entry><entry>
    <title>ELI5: Upcoming Developments in Ember.js</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/10/upcoming-developments-ember" />
    <id>https://dockyard.com/blog/2016/08/10/upcoming-developments-ember</id>
    
    <published>2016-08-10 00:00:00</published>
    <updated>2016-08-27 10:02:01</updated>
    <author><name>Rowan Krishnan</name></author>
    <summary>A brief tour of Ember&#39;s future through a few RFCs.</summary>
    <content type="html">&lt;h1&gt;ELI5: Upcoming Developments in Ember.js&lt;/h1&gt;

&lt;p&gt;As a newcomer to &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember&lt;/a&gt; in the past few months, it&amp;#39;s been fascinating to not only learn how to build applications with a great JS framework, but also to gain insight into how a massive and popular open source project grows and absorbs new ideas. Although I&amp;#39;m probably a little bit biased at this point, I believe Ember does a better job than most at managing and encouraging this process.&lt;/p&gt;

&lt;p&gt;The primary channel for discussion of introducing new features into Ember is the &lt;a href=&quot;https://github.com/emberjs/rfcs&quot;&gt;public RFC repository&lt;/a&gt; on GitHub. RFCs, which stand for &amp;#39;Request For Comment&amp;#39;, are pull requests in which any developer can outline a feature specification and open the floor for comments and criticism. This is what true open source looks like, and the success of the RFC repo represents to me the best aspects of the Ember community. &lt;/p&gt;

&lt;p&gt;All of that being said, it can certainly be a little intimidating for someone new to the framework to dive right in and catch up on the most significant RFCs being discussed. So I decided to do a little write up that made that easier.&lt;/p&gt;

&lt;p&gt;Here are the three RFCs that have provoked the most discussion, and perhaps demonstrate what the future of Ember looks like:&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/emberjs/rfcs/pull/143&quot;&gt;Module Unification&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Create a unified pattern for organizing and naming modules in Ember projects that is deterministic, extensible, and ergonomic.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This seems like the best one to start with, since it&amp;#39;s the one most likely to affect all users of Ember and dramatically impact daily use of the framework. In short, this RFC aims to provide an improved ergonomic directory structure for all new Ember projects.&lt;/p&gt;

&lt;p&gt;Why? Well, there are unfortunately a few too many deficiencies with the current system of organizing Ember modules.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers have to decide between using the pod or classic app structure.&lt;/li&gt;
&lt;li&gt;Addons are directly mixed into the codebase and therefore present opportunities for name collision.&lt;/li&gt;
&lt;li&gt;Module resolution rules are esoteric and inefficient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The proposed solution to these problems does a major refactor of default Ember app structure. Replacing &lt;code&gt;app&lt;/code&gt; at the top level is a new directory called &lt;code&gt;src&lt;/code&gt; which can contain several subdirectories (&lt;code&gt;data&lt;/code&gt;, &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;ui&lt;/code&gt;, &lt;code&gt;utils&lt;/code&gt;, and &lt;code&gt;services&lt;/code&gt;). Here&amp;#39;s an example of what this could look like in a blogging application, as shown in the RFC:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
52
53
54
55
56
57
58
59
&lt;strong&gt;60&lt;/strong&gt;
61
62
63
64
65
66
67
68
69
&lt;strong&gt;70&lt;/strong&gt;
71
72
73
74
75
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;src
  data
    models
      author.js
      comment
        adapter.js
        model.js
        serializer.js
      post
        adapter.js
        model.js
        serializer.js
    transforms
      date.js
  init
    initializers
      i18n.js
    instance-initializers
      auth.js
  services
    auth.js
  ui
    components
      capitalize.js
      date-picker
        component.js
        template.hbs
      list-paginator
        component.js
        template.hbs
        paginator-control
          component.js
          template.hbs
    partials
      footer.hbs
    routes
      application
        template.hbs
      index
        template.hbs
        route.js
        controller.js
      posts
        -components
          capitalize.js
          titleize.js
          -utils
            strings.js
        post
          -components
            post-viewer
              component.js
              template.hbs
          edit
            -components
              post-editor
                post-editor-button
                  component.js
                  template.hbs
                calculate-post-title.js
                component.js
                template.hbs
            route.js
            template.hbs
          route.js
          template.hbs
        route.js
        template.hbs
    styles
      app.scss
    index.html
  utils
    md5.js
  main.js
  router.js
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There are a couple of examples of this in action; namely the &lt;a href=&quot;https://github.com/rwjblue/--ghost-modules-sample/tree/grouped-collections/src&quot;&gt;Ghost Admin&lt;/a&gt; and &lt;a href=&quot;https://github.com/rwjblue/--travis-modules-sample/tree/modules/src&quot;&gt;Travis Client&lt;/a&gt;. &lt;a href=&quot;https://twitter.com/rwjblue&quot;&gt;Rob Jackson&lt;/a&gt; has also done a fantastic job in releasing a &lt;a href=&quot;https://github.com/rwjblue/ember-module-migrator&quot;&gt;tool&lt;/a&gt; that allows us to migrate our apps over to this new structure.&lt;/p&gt;

&lt;p&gt;The RFC goes into a great amount of detail regarding other changes that will need to take place, such as renaming and reorganizing modules, and a refactor of the Ember Resolver. You can read the whole thing &lt;a href=&quot;https://github.com/dgeb/rfcs/blob/module-unification/text/0000-module-unification.md&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/emberjs/rfcs/pull/119&quot;&gt;Testing Unification&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;The goal of this RFC is to unify the concepts amongst the various types of test (acceptance, integration, and unit) and provide a single common structure to tests.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Look, most of us don&amp;#39;t really love writing tests. It&amp;#39;s okay to admit it. But as &lt;a href=&quot;https://github.com/rwjblue&quot;&gt;Rob Jackson&lt;/a&gt; explains in his RFC, Ember&amp;#39;s testing story is coming together quite nicely, and it&amp;#39;s never been easier to write comprehensive tests across all the various pieces of your app (routes, components, templates, etc). One of the best aspects of Ember being a &amp;quot;full featured&amp;quot; framework is that it comes packaged with all the libraries and tools you&amp;#39;d need to write great tests, with as little friction as possible.&lt;/p&gt;

&lt;p&gt;The only persisting problem is that these tests look and function quite different from one another. Specifically, they handle things like asynchronous requests differently and use unique sets of helpers. This RFC seeks to &amp;quot;unify&amp;quot; the three types of tests - acceptance, integration, and unit - by introducing new syntax to handle asynchronous test actions, and establishing a set of test helpers that would be shared across the three types of tests.&lt;/p&gt;

&lt;p&gt;Like the &lt;a href=&quot;https://github.com/emberjs/rfcs/pull/143&quot;&gt;Module Unification RFC&lt;/a&gt;, this one goes into a great amount of detail that eclipses the scope of an ELI5. I highly recommend checking it out the &lt;a href=&quot;https://github.com/rwjblue/rfcs/blob/42/text/0000-grand-testing-unification.md&quot;&gt;full spec&lt;/a&gt; if you&amp;#39;re interested in the future of testing.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/emberjs/rfcs/pull/38&quot;&gt;Routable Components&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Eliminates Controllers.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ah, yes. The Holy Grail of RFCs. The future of Ember. The promised land.&lt;/p&gt;

&lt;p&gt;In all seriousness, routable components are a pretty big deal, and received an appropriately large reaction when first presented at EmberConf 2015 by &lt;a href=&quot;https://github.com/tomdale&quot;&gt;Tom Dale&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://github.com/wycats&quot;&gt;Yehuda Katz&lt;/a&gt;. It&amp;#39;s been a long time since then, and if you&amp;#39;ve been following along, you might need a little refresher on how they are intended to work.&lt;/p&gt;

&lt;p&gt;As the description above concisely states, routable components essentially mean the death and deprecation of controllers. This is a good thing. For many months now, controllers have been a key point of confusion for new developers, and stick out as a remnant of pre-2.0 Ember. One of the biggest complaints about the framework in the early years was that the architectural pattern was far too complicated (&amp;quot;MVC? MVVM? What&amp;#39;s the difference between a view and a controller?&amp;quot;). Ember continuing to simplify and mature these patterns is great news.&lt;/p&gt;

&lt;p&gt;Routable components hope to replace controllers by absorbing the few functional responsibilities that they still have, such as query parameters and setting a route&amp;#39;s model on the template or top-level component. Discussing the implementation for these changes, however, is a tricky subject due to the length of time passed since the concept of routable components was first introduced. Original proposals included removing older model hooks (such as &lt;code&gt;beforeModel&lt;/code&gt; and &lt;code&gt;afterModel&lt;/code&gt;) and introducing a new, automatically invoked hook called &amp;quot;attributes&amp;quot;, that would allow a route to specify the positional and query parameters to be passed into a rendered component.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Phoenix Channels vs Rails Action Cable</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/09/phoenix-channels-vs-rails-action-cable" />
    <id>https://dockyard.com/blog/2016/08/09/phoenix-channels-vs-rails-action-cable</id>
    
    <published>2016-08-09 00:00:00</published>
    <updated>2016-08-10 21:43:18</updated>
    <author><name>Chris McCord</name></author>
    <summary>comparing phoenix and rails real-time performance</summary>
    <content type="html">&lt;p&gt;At DockYard, we transitioned our backend development from Ruby and Rails to Elixir and Phoenix once it became clear that Phoenix better served our clients needs to take on the modern web. As we&amp;#39;ve seen, &lt;a href=&quot;https://dockyard.com/blog/2015/11/18/phoenix-is-not-rails&quot;&gt;Phoenix is Not Rails&lt;/a&gt;, but we borrow some of their great ideas. We were also delighted to give back in the other direction when Rails announced that Rails 5.0 would be shipping with Action Cable â a feature that takes inspiration from Phoenix Channels.&lt;/p&gt;

&lt;p&gt;Now that Rails 5.0 has been released, we have clients with existing Rails stacks asking if they should use Action Cable for their real-time features, or jump to Phoenix for more reliable and scalable applications. When planning architecture decisions, in any language or framework, you should always take measurements to prove out your assumptions and needs. To measure how Phoenix channels and Action Cable handle typical application work-flows, we created a chat application in both frameworks and stressed each through varying levels of workloads.&lt;/p&gt;

&lt;h2&gt;How the tests were designed&lt;/h2&gt;

&lt;p&gt;For our measurements, we used the &lt;a href=&quot;http://tsung.erlang-projects.org&quot;&gt;tsung&lt;/a&gt; benchmarking client to open WebSocket connections to each application. We added XML configuration to send specific Phoenix and Rails protocol messages to open channels on the established connection and publish messages. For hardware, we used two Digital Ocean 16GB, 8-core instances for the client and server.&lt;/p&gt;

&lt;p&gt;The work-flows for each tsung client connection were as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;open a WebSocket connection to the server&lt;/li&gt;
&lt;li&gt;create a single channel subscription on the connection, to a chat room chosen at random&lt;/li&gt;
&lt;li&gt;Periodically send a message to the chat room, randomly once every 10s-60s to simulate messaging across members in the room&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the server, the channel code for Rails and Phoenix is quite simple:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule Chat.RoomChannel do
  use Chat.Web, :channel

  def join(&amp;quot;room:&amp;quot; &amp;lt;&amp;gt; _id, _params, socket) do
    {:ok, socket}
  end

  def handle_in(&amp;quot;publish_msg&amp;quot;, %{&amp;quot;body&amp;quot; =&amp;gt; body, &amp;quot;user&amp;quot; =&amp;gt; user}, socket) do
    broadcast!(socket, &amp;quot;new_message&amp;quot;, %{body: body, user: user})
    {:reply, :ok, socket}
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;RoomsChannel&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ApplicationCable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Channel&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;subscribed&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@topic&lt;/span&gt; = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;rooms:&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;rand(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;integer&quot;&gt;8&lt;/span&gt;)&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    stream_from &lt;span class=&quot;instance-variable&quot;&gt;@topic&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;publish_msg&lt;/span&gt;(data)
    &lt;span class=&quot;constant&quot;&gt;ActionCable&lt;/span&gt;.server.broadcast(&lt;span class=&quot;instance-variable&quot;&gt;@topic&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;body&lt;/span&gt;: data[&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;],
      &lt;span class=&quot;key&quot;&gt;username&lt;/span&gt;: data[&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;],
      &lt;span class=&quot;key&quot;&gt;started&lt;/span&gt;: data[&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;started&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]
    )
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After establishing N numbers of rooms, with varying numbers of users per room, we measured each application&amp;#39;s responsiveness. We tested performance by joining a random room from the browser and timing the broadcasts from our local browser to all members in the room. As we increased the numbers of users per room, we measured the change in broadcast latency. We recorded short clips of each application&amp;#39;s behavior under different loads.&lt;/p&gt;

&lt;p&gt;This simulates a &amp;quot;chat app&amp;quot;, but the work-flow applies equally to a variety of applications; real-time updates to visitors reading articles, streaming feeds, collaborative editors, and so on. As we evaluate the results, we&amp;#39;ll explore how the numbers relate to different kinds of applications.&lt;/p&gt;

&lt;h2&gt;Rails Memory Leaks&lt;/h2&gt;

&lt;p&gt;After creating the Rails chat application, setting up redis, and deploying the application to our instance, we immediately observed a memory leak in the application that was visible just by refreshing a browser tab and watching the memory grow; to never be freed. The following recording shows this in action (sped up 10x):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/jQOIhkX.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;We searched recently reported bugs around this area, and found an issue related to Action Cable &lt;a href=&quot;https://github.com/rails/rails/pull/25615/files&quot;&gt;failing to call &lt;code&gt;socket.close&lt;/code&gt; when cleaning up connections&lt;/a&gt;. This patch has been applied to the &lt;code&gt;5-0-stable&lt;/code&gt; branch, so we updated the app to the unreleased branch and re-ran the tests. The memory leak persisted.&lt;/p&gt;

&lt;p&gt;We haven&amp;#39;t yet isolated the source of the leak, but given the simplicity of the channel code, it must be within the Action Cable stack. This leak is particularly concerning since Rails 5.0 has been released for some time now and the &lt;code&gt;5-0-stable&lt;/code&gt; branch itself has unreleased memory leak patches going back greater than 30 days.&lt;/p&gt;

&lt;h2&gt;Scalability&lt;/h2&gt;

&lt;p&gt;We set the memory leak issue aside and proceeded with our tests for the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Max numbers of rooms supported by a single server, with 50 users per room&lt;/li&gt;
&lt;li&gt;Max numbers of rooms supported by a single server, with 200 users per room&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: For Phoenix, for every scenario we maxed the &lt;em&gt;client server&amp;#39;s&lt;/em&gt; ability to open more WebSocket connections, giving us 55,000 users to simulate for our tests. Browser -&gt; Server latency should also be considered when evaluating broadcast latency in these tests.&lt;/p&gt;

&lt;h3&gt;50 users per room&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rails&lt;/strong&gt;: 50 rooms, 2500 users:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/l8mJ966.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Responsiveness was speedy at 50 rooms, so we upped the room count to 75, giving us 3750 users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rails:&lt;/strong&gt; 75 rooms, 3750 users:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/2Mb2gpT.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Here, we can see Action Cable falling behind on availability when broadcasting, with messages taking an average of 8s to be broadcast to all 50 users for the given room. For most applications, this level of latency is not acceptable, so the level of performance for maxinum rooms on this server would be somewhere between 50 and 75 rooms, given 50 users per room.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phoenix:&lt;/strong&gt; 1100 rooms, 55,000 users (maxed 55,000 client connections)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/0Qu0pM5.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;We can see that Phoenix responds on average in 0.25s, and only is maxed at 1100 rooms because of the 55,000 client limit on the tsung box.&lt;/p&gt;

&lt;h3&gt;Making sense of the results, 50 users per room&lt;/h3&gt;

&lt;p&gt;These results show that if you are building an application for small to medium sized businesses, if 75 companies visit the app at the same time, their notifications will be delayed. Given the severe degradation in performance from 50 to 75 rooms, it may also be hard to pinpoint your server density when planning for load.&lt;/p&gt;

&lt;p&gt;For load planning, horizontal scalability will be required with 50-75 companies per server, but the reliance on redis should be considered as a central bottleneck. Horizontal scalability was the obvious choice for Ruby when it came to stateless HTTP requests, but we can see why vertical scalability becomes increasingly important for stateful connections. If you require dozens or hundreds of servers, Action Cable will still rely on a central redis bottleneck for PubSub.&lt;/p&gt;

&lt;h3&gt;200 users per room&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rails:&lt;/strong&gt; 8 rooms, 1600 users:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/rBbjAxr.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;We can see Action Cable starts off with acceptable latency, but begins to quickly fall behind as broadcast latency grows with each message. Broadcast latency grows longer than 10s. Next, we upped the room count by 1, to see where the limit was.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rails:&lt;/strong&gt; 9 rooms, 1800 users before availability was compromised when broadcasting.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/S7tpHLm.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;At 200 users per room, Action Cable is unable to maintain the broadcast load and supported just 9 rooms before we experienced messages stop arriving or subscriptions failing to establish. At these levels, the only consistent performance we could get for 200 users per room, was limiting the server to 7 rooms, or 1400 users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phoenix:&lt;/strong&gt; 275 rooms, 55,000 users (maxed 55,000 client connections)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/noizwRP.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;We can see that Phoenix responds on average in 0.24s, and only is maxed at 275 rooms because of the 55,000 client limit on the tsung box. Additionally, it&amp;#39;s important to note that Phoenix maintains the same responsiveness when broadcasting for both the 50 and 200 users per room tests.&lt;/p&gt;

&lt;h3&gt;Making sense of the results, 200 users per room&lt;/h3&gt;

&lt;p&gt;You may be thinking, &amp;quot;but my application isn&amp;#39;t a chat app, and only needs simple page updates&amp;quot;. These tests apply equally to many scenarios. Imagine you have an information system where you want to publish periodic updates to pages. This could be for a news site where visitors see new comments, or a booking site where visitors see &amp;quot;20 other people are currently viewing this hotel&amp;quot;.&lt;/p&gt;

&lt;p&gt;This tests shows that if your app receives a sudden spike in visitors and more than 7 articles have 200 or more readers, the server won&amp;#39;t be able to keep up with the notification demand for both the popular articles, &lt;em&gt;as well as the low traffic ones&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For a booking site, imagine 7 hotels across the country release a discount rate and customers jump online for the deal. Suddenly, you need to spin up extra servers to maintain booking notifications, and the severity of the delays becomes worse if critical functionality of your application relies on these notifications.&lt;/p&gt;

&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;If memory leaks can be ruled out or addressed, the sweet-spot for Action Cable today is small workloads with few subscribers on any given topic. Going beyond this means engineering efforts and resources must be spent on managing multiple nodes and optimizing code out of channels. Higher workloads with broadcasts to more than a few dozen subscribers risks availability. With Phoenix, we&amp;#39;ve shown that channels performance remains consistent as notification demand increases, which is essential for handling traffic spikes and avoiding overload. &lt;/p&gt;

&lt;p&gt;When I started my own real-time Rails features with &lt;a href=&quot;https://github.com/chrismccord/render_sync&quot;&gt;Sync&lt;/a&gt; several years ago, memory leaks and consistent performance were my main fears that drove me to look elsewhere, find Elixir, and create Phoenix. The rails-core team has done a great job putting a real-time story in place, but wrangling Ruby&amp;#39;s lack of concurrency features will continue to be a challenge.&lt;/p&gt;

&lt;p&gt;The source code and instructions for running these tests on your own hardware can be found &lt;a href=&quot;https://github.com/chrismccord/channelsac&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Understanding the &amp; (capture operator) in Elixir</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/05/understand-capture-operator-in-elixir" />
    <id>https://dockyard.com/blog/2016/08/05/understand-capture-operator-in-elixir</id>
    
    <published>2016-08-05 00:00:00</published>
    <updated>2016-08-10 21:43:18</updated>
    <author><name>Daniel Xu</name></author>
    <summary>how to use &amp; (capture operator) in Elixir</summary>
    <content type="html">&lt;h1&gt;Understanding the &amp;amp; (capture operator) in Elixir&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; is the capture operator in Elixir, it is used to &lt;strong&gt;capture&lt;/strong&gt; and &lt;strong&gt;create&lt;/strong&gt; anonymous functions.&lt;/p&gt;

&lt;h2&gt;Anonymous functions and arity&lt;/h2&gt;

&lt;p&gt;Before going into details about the capture operator, let&amp;#39;s get familiar with &lt;code&gt;anonymous functions&lt;/code&gt; and &lt;code&gt;arity&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;Given the following example:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;add_one = fn x -&amp;gt; x + 1 end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;we defined a function, but it isn&amp;#39;t bound to a global name, so it is an anonymous functions or a lambda.&lt;/p&gt;

&lt;p&gt;This function takes one argument, so its arity is 1.&lt;/p&gt;

&lt;h2&gt;How to use &lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/h2&gt;

&lt;h3&gt;capture function&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s first talk about capturing function.
Capture means &lt;code&gt;&amp;amp;&lt;/code&gt; can turn a function into an &lt;code&gt;anonymous functions&lt;/code&gt; which can be passed as arguments to other function or be bound to a variable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; can capture two types of functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;function with given name and arity from a module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The notation is: &lt;code&gt;&amp;amp;(module_name.function_name/arity)&lt;/code&gt;, e.g.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;speak = &amp;amp;(IO.puts/1)
speak.(&amp;quot;hello&amp;quot;)  # hello
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We capture &lt;code&gt;puts&lt;/code&gt; function from &lt;code&gt;IO&lt;/code&gt; module and bind it with a local name &lt;code&gt;speak&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the following example, &lt;code&gt;put_in_columns&lt;/code&gt; and &lt;code&gt;put_in_one_row&lt;/code&gt; are defined in the same module, so we can capture &lt;code&gt;put_in_one_row&lt;/code&gt; by
&lt;code&gt;&amp;amp;put_in_one_row/1&lt;/code&gt;, notice that we don&amp;#39;t include the module name here.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule Issues.TableFormatter do
  def put_in_columns(data_by_columns, format) do
     Enum.each(data_by_columns, &amp;amp;put_in_one_row/1)
  end

  def put_in_one_row(fields) do
     # Do some things...
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;create anonymous functions&lt;/h3&gt;

&lt;p&gt;The capture operator can also be used to create anonymous functions, for example:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;add_one = &amp;amp;(&amp;amp;1 + 1)
add_one.(1) # 2
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;is the same with:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;add_one = fn x -&amp;gt; x + 1 end
add_one.(1) # 2
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You might notice that &lt;code&gt;&amp;amp;1&lt;/code&gt; is used in the above example. That&amp;#39;s called a value placeholder, and it identifies the &lt;code&gt;nth&lt;/code&gt; argument of the function&lt;/p&gt;

&lt;p&gt;In addition, as &lt;code&gt;{}&lt;/code&gt; and &lt;code&gt;[]&lt;/code&gt; are also operators in Elixir, &lt;code&gt;&amp;amp;&lt;/code&gt; can work with them too.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;return_list = &amp;amp;[&amp;amp;1, &amp;amp;2]
return_list.(1, 2) # [1, 2]

return_tuple = &amp;amp;{&amp;amp;1, &amp;amp;2}
return_tuple.(1, 2) # {1, 2}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s hard to comprehend at first, we just need to think about it from another perpective:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://monosnap.com/file/RfDoLHTqzOzGGXetAoUfUvVwPpAf5j.png&quot; alt=&quot;Alt text&quot;&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Measuring the unknown</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/05/measuring-the-unknown" />
    <id>https://dockyard.com/blog/2016/08/05/measuring-the-unknown</id>
    
    <published>2016-08-05 00:00:00</published>
    <updated>2016-08-11 17:06:54</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Estimating the size of an unknown project can be tough. But you know more than you think you do.</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/KlXdtAE.jpg&quot; alt=&quot;Painted planets on a background of stars&quot;&gt;&lt;/p&gt;

&lt;p&gt;As a designer, I often get the opportunity to participate in starting and planning projects. Some projects have many unknowns, and we follow a Discovery process before proposing a blueprint for what to build, and why. And sometimes, we need to understand the scale of a challenge without following this familiar discovery process. &lt;/p&gt;

&lt;h2&gt;Now, please measure the unknown&lt;/h2&gt;

&lt;p&gt;At first, it may seem impossible: how can I âsize upâ a solution to a problem without knowing all the variables, and the potential ranges for each one? How can I estimate when the thing I am measuring feels like a black box?&lt;/p&gt;

&lt;p&gt;If you step back from the problem, however, you may find that you know more than you think. This situation reminds me of an example a Mathematics professor gave me to explain how they work with abstract concepts. &lt;/p&gt;

&lt;h2&gt;Start by measuring the infinity&lt;/h2&gt;

&lt;p&gt;Letâs say youâre trying to measure an infinite thing. Imagine if  you were to remove two walls and the ceiling from the room youâre sitting in. Take in all the space, stretching out into the cosmos â in front, to your left and above you (but not the other four quadrants.) It is, indeed, an infinite amount of space that you couldnât measure in familiar ways - but what you do know is that itâs smaller than the other three quarters you did not include. &lt;/p&gt;

&lt;p&gt;By itself, a thing can feel immeasurable, but in the context of other like things, you can easily size it up.&lt;/p&gt;

&lt;h2&gt;Decide what kind of infinity it is&lt;/h2&gt;

&lt;p&gt;Your problem might still feel like a black box. Thatâs fine. Shake the box a bit - does it rattle? How does it behave? What youâre trying to get at is the structure, rather than the size or weight.&lt;/p&gt;

&lt;p&gt;Structure corresponds to design intent, versus the weight and size deals with implementation. The intent of a bridge is fundamentally different from the intent of a house. They are meant to behave differently, even though the size, materials and construction techniques could be similar. If you can reliably say that youâre building a bridge, and itâs smaller than any of the previous three bridges youâve seen - you can have a good amount of certainty that the project will fall between X and Y size.&lt;/p&gt;

&lt;p&gt;Even more importantly, by calling the project a bridge, youâve now reduced the number of confusing variables youâre working with. You and your team can how have a conversation around how long, and how strong the bridge needs to be, but youâre not worrying about whether it needs to fly, or have a patio in the front.&lt;/p&gt;

&lt;h2&gt;No one has all the answers&lt;/h2&gt;

&lt;p&gt;As professionals, we often feel like we should have all the answers. But no one can have them all. True professionalism means being honest about what you donât know while doing our homework to narrow down the infinity to something we can address intelligently.&lt;/p&gt;

&lt;p&gt;Scientists do this all the time. We measure far away planets by looking at very scarce data and comparing it to what we know. As we learn more, whole theories get rewritten and replaced. But if we donât start with the theory we have, and make a good attempt at solving a problem, we will never learn more. &lt;/p&gt;

&lt;p&gt;The opposite of knowing isnât not-knowing. Itâs not trying. We must share openly what we donât know and, in case of a design discovery, document assumptions and caveats. If weâre sizing up an unknown bridge, be vocal about your assumption that the bridge posts are not underwater (thatâd triple their cost and complexity) or resting on a volcano (good luck). Your black box may contain an infinity, but by describing it and naming it youâve gone a long way towards answering, âhow large?â &lt;/p&gt;
</content>
  </entry><entry>
    <title>We&#39;re looking for an HTML/CSS Specialist!</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/04/looking-for-a-uxd-senior" />
    <id>https://dockyard.com/blog/2016/08/04/looking-for-a-uxd-senior</id>
    
    <published>2016-08-04 00:00:00</published>
    <updated>2016-08-04 21:40:52</updated>
    <author><name>Cory Tanner</name></author>
    <summary>Join our DockYard team on some exciting incoming projects</summary>
    <content type="html">&lt;p&gt;If you have a passion for HTML and CSS we want you at DockYard!&lt;/p&gt;

&lt;p&gt;Weâre a premiere design-first web consultancy based in Boston and we are looking for DockYarders to join our growing team.&lt;/p&gt;

&lt;p&gt;Our workflow involves three steps. Designers hand off mockups to the HTML/CSS specialists who then give styled templates to engineers. Traditionally writing HTML and CSS was the responsibility of designers or engineers but with the growth of HTML5 and CSS you need a role within the team solely focused on HTML and CSS.&lt;/p&gt;

&lt;p&gt;As an HTML &amp;amp; CSS specialist at DockYard you will be in a unique position where you will work closely and engage in great communication with both the Design team and Engineering team to help facilitate the handoff between visual design and app implementation. Additionally to that, you&amp;#39;ll be challenged with helping drive the creation of web applications and solving interesting problems regarding accessibility, browser compatibility, standards compliance, and responsive design.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dockyard.com/contact/join-us&quot;&gt;Send us a note&lt;/a&gt; - we are looking forward to hearing from you!&lt;/p&gt;
</content>
  </entry><entry>
    <title>We&#39;re looking for a designer!</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/08/03/looking-for-a-designer" />
    <id>https://dockyard.com/blog/2016/08/03/looking-for-a-designer</id>
    
    <published>2016-08-03 00:00:00</published>
    <updated>2016-08-04 14:32:47</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Join our DockYard team on some exciting incoming projects</summary>
    <content type="html">&lt;p&gt;Weâve got several exciting projects lined up, and weâre looking to grow the
design team on a per-project basis.&lt;/p&gt;

&lt;p&gt;Weâre looking for a designer with strength in both UX and visual design. Design
research experience would be a plus.&lt;/p&gt;

&lt;p&gt;For this project, you would be paired up with a DockYard designer to help lead
a 4-6 week product discovery. You would get the opportunity to see a product
through from conception to finished visual designs, user testing, and even
collaboration with Engineers. Our sprint-based, focused approach to working,
in close collaboration with our team and the client, is ideal for achieving
deep, high quality work.&lt;/p&gt;

&lt;p&gt;This contract engagement would be ideal for a mid- to senior designer looking to
expand their toolkit, and collaborate closely with a premier web application
consultancy. This opportunity could lead to a full time position in the future,
based on a 32-hour workweek.&lt;/p&gt;

&lt;p&gt;This contract requires you to be in-person at our office in Boston for the duration.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dockyard.com/contact/join-us&quot;&gt;Send us a note&lt;/a&gt; - weâre looking forward
to hearing from you!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Patterns from Ember Composable Helpers</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/07/27/patterns-from-composable-helpers" />
    <id>https://dockyard.com/blog/2016/07/27/patterns-from-composable-helpers</id>
    
    <published>2016-07-27 00:00:00</published>
    <updated>2016-07-28 15:11:49</updated>
    <author><name>Marten Schilstra</name></author>
    <summary>A walkthrough of one of the patterns used in Ember Composable Helpers</summary>
    <content type="html">&lt;p&gt;Co-creator of Ember Composable Helpers &lt;a href=&quot;https://twitter.com/sugarpirate_&quot;&gt;Lauren Tan&lt;/a&gt; recently wrote about the &lt;a href=&quot;https://dockyard.com/blog/2016/04/18/ember-composable-helpers&quot;&gt;what, why and how&lt;/a&gt; of Ember Composable Helpers.
Now I&amp;#39;d like to talk about one of the patterns we have used to make Ember Composable Helpers work.&lt;/p&gt;

&lt;h2&gt;The fundament of the array helpers is the get helper&lt;/h2&gt;

&lt;p&gt;Most of the array helpers are built upon the implementation of the &lt;a href=&quot;https://github.com/jmurphyau/ember-get-helper/blob/master/addon/helpers/get-glimmer.js&quot;&gt;get helper&lt;/a&gt;. 
Let&amp;#39;s take a closer look at a simplified version of the &lt;code&gt;get&lt;/code&gt; helper:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { 
  Helper, 
  get,
  set,
  observer,
  defineProperty,
  &lt;span class=&quot;key&quot;&gt;computed&lt;/span&gt;: { oneWay }
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Helper.extend({
  compute([targetObject, propertyPath]) {
    set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;targetObject&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, targetObject);
    set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;propertyPath&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, propertyPath);

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  },

  &lt;span class=&quot;key&quot;&gt;propertyPathDidChange&lt;/span&gt;: observer(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;propertyPath&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    let propertyPath = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;propertyPath&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    defineProperty(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, oneWay(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;targetObject.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{propertyPath}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;));
  }),

  &lt;span class=&quot;key&quot;&gt;contentDidChange&lt;/span&gt;: observer(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.recompute();
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s start with the &lt;code&gt;compute&lt;/code&gt; function on lines 13-18. 
It expects a &lt;code&gt;targetObject&lt;/code&gt; and &lt;code&gt;propertyPath&lt;/code&gt; param, which stands for the object you want to get the given property from.
These params are set as properties on the helper itself each time &lt;code&gt;compute&lt;/code&gt; is called. Finally the &lt;code&gt;compute&lt;/code&gt; function returns the &lt;code&gt;content&lt;/code&gt; property. This will be the result of getting the &lt;code&gt;propertyPath&lt;/code&gt; from the &lt;code&gt;targetObject&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Why not just return the given property from the target object?&lt;/h2&gt;

&lt;p&gt;Well, writing the helper as follows would have the downside that it will only recompute whenever the &lt;code&gt;targetObject&lt;/code&gt; changes or when the &lt;code&gt;propertyPath&lt;/code&gt; changes, but not when the desired property on the target object changes.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { &lt;span class=&quot;key&quot;&gt;Helper&lt;/span&gt;: { helper }, get } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;getHelper&lt;/span&gt;([targetObject, propertyPath]) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; get(targetObject, propertyPath);
}

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; helper(getHelper);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Solution: Observers&lt;/h2&gt;

&lt;p&gt;Yes you heard it right, observers are a perfect candidate to solve the problem that our helper won&amp;#39;t recompute when we want it to. So let&amp;#39;s take a look at the &lt;code&gt;propertyPathDidChange&lt;/code&gt; and &lt;code&gt;contentDidChange&lt;/code&gt; observers.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;propertyPathDidChange: observer(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;propertyPath&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  let propertyPath = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;propertyPath&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  defineProperty(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, oneWay(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;targetObject.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{propertyPath}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;));
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let me explain what happens with this observer. On the first line we define an observer that will be triggered every time &lt;code&gt;propertyPath&lt;/code&gt; gets updated. In the function body we get the value of &lt;code&gt;propertyPath&lt;/code&gt; and use it to define a new computed property &lt;em&gt;at runtime&lt;/em&gt;. We do that using &lt;a href=&quot;http://emberjs.com/api/classes/Ember.html#method_defineProperty&quot;&gt;&lt;code&gt;defineProperty&lt;/code&gt;&lt;/a&gt;. This means that every time the &lt;code&gt;propertyPath&lt;/code&gt;&amp;#39;s value changes, the &lt;code&gt;content&lt;/code&gt; computed property gets redefined to point towards the correct path on the target object.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;contentDidChange: observer(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.recompute();
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then there is the &lt;code&gt;contentDidChange&lt;/code&gt; observer. This one watches for changes of the &lt;code&gt;content&lt;/code&gt; property, which we define with the &lt;code&gt;propertyPathDidChange&lt;/code&gt; observer. The &lt;code&gt;contentDidChange&lt;/code&gt; observer calls &lt;code&gt;recompute&lt;/code&gt;, which recomputes the end value of the helper.&lt;/p&gt;

&lt;h2&gt;Putting it all together to create the map-by helper&lt;/h2&gt;

&lt;p&gt;Now that we know how to build a helper that can recompute when a property that we only know of at runtime changes, it is very simple to create other similar helpers upon this pattern. I&amp;#39;ll leave you with the &lt;code&gt;map-by&lt;/code&gt; helper, which doesn&amp;#39;t look that different from the &lt;code&gt;get&lt;/code&gt; helper I&amp;#39;ve shown you.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { 
  Helper, 
  get,
  set,
  isEmpty,
  observer,
  defineProperty,
  &lt;span class=&quot;key&quot;&gt;computed&lt;/span&gt;: { mapBy }
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Helper.extend({
  compute([byPath, array]) {
    set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, array);
    set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;byPath&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, byPath);

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  },

  &lt;span class=&quot;key&quot;&gt;byPathDidChange&lt;/span&gt;: observer(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;byPath&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    let byPath = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;byPath&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (isEmpty(byPath)) {
      defineProperty(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, []);
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;;
    }

    defineProperty(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, mapBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, byPath));
  }),

  &lt;span class=&quot;key&quot;&gt;contentDidChange&lt;/span&gt;: observer(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.recompute();
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;</content>
  </entry><entry>
    <title>How to use git bisect by example</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/07/26/how-to-bisect-ember" />
    <id>https://dockyard.com/blog/2016/07/26/how-to-bisect-ember</id>
    
    <published>2016-07-26 00:00:00</published>
    <updated>2016-08-04 14:32:47</updated>
    <author><name>Marten Schilstra</name></author>
    <summary>Learn how to use Git&#39;s bisect command with Ember.js as the example</summary>
    <content type="html">&lt;p&gt;I&amp;#39;m writing this tutorial because I ran into a problem, while working on an addon, with Ember.js the other day. The problem was that the test suite did not pass anymore on Ember.js&amp;#39; canary build channel, while it used to pass before. After debugging the problem I wanted to find out which commit in Ember.js did break the tests. Thanks to &lt;a href=&quot;https://twitter.com/rwjblue&quot;&gt;Robert Jackson&lt;/a&gt;, who pointed me to a &lt;a href=&quot;https://github.com/emberjs/ember.js/issues/13846#issuecomment-234133694&quot;&gt;GitHub comment&lt;/a&gt;, I&amp;#39;ve been able to use &lt;code&gt;git bisect&lt;/code&gt; to find the commit that introduced the issue and &lt;a href=&quot;https://github.com/emberjs/ember.js/issues/13888&quot;&gt;report&lt;/a&gt; it.&lt;/p&gt;

&lt;h3&gt;What bisect does&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git bisect&lt;/code&gt; uses the &lt;a href=&quot;https://en.wikipedia.org/wiki/Bisection_method&quot;&gt;bisection method&lt;/a&gt; to find the first commit that introduced the bug you are looking for. You will have to tell the bisect command one commit you are sure contains the bug and one commit that you are sure of that it does not contain the bug. Bisect will then start searching, asking you if a given commit it proposes is good or bad, until it has found the commit that introduces your bug.&lt;/p&gt;

&lt;h3&gt;Setting up before the bisect&lt;/h3&gt;

&lt;p&gt;To find out what commit has introduced a bug in the &lt;a href=&quot;https://github.com/emberjs/ember.js&quot;&gt;Ember.js&lt;/a&gt; repository, you need to clone a different repository, that is &lt;a href=&quot;https://github.com/components/ember&quot;&gt;&lt;code&gt;components/ember&lt;/code&gt;&lt;/a&gt;, which contains the Bower builds of Ember.js. You can link this repo to your app directly and then use &lt;code&gt;git bisect&lt;/code&gt; to find the first build that contains the bug. You can then cross-reference the build with the real Ember.js repo to find the actual commit that introduced the bug.&lt;/p&gt;

&lt;p&gt;To clone and link the &lt;code&gt;components/ember&lt;/code&gt; repository:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;git clone git@github.com:components/ember.git components-ember -b canary
cd components-ember
bower link
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now you need to do a little bit of setup in the app that you are working with. You will need to modify your &lt;code&gt;bower.json&lt;/code&gt; to use &lt;code&gt;components/ember#canary&lt;/code&gt; for Ember.js and then link it to the local repository you just cloned. I recommend you do this in a seperate terminal window/tab, as you will have to go back and forth between this and the other a few times.&lt;/p&gt;

&lt;p&gt;Example &lt;code&gt;bower.json&lt;/code&gt; after the change:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;my-app&amp;quot;,
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;ember&amp;quot;: &amp;quot;components/ember#canary&amp;quot;
  },
  &amp;quot;resolutions&amp;quot;: {
    &amp;quot;ember&amp;quot;: &amp;quot;canary&amp;quot;
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After updating your &lt;code&gt;bower.json&lt;/code&gt; remove the installed Ember Bower component and link it to the local one.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;rm -rf bower_components/ember
bower link ember
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now you&amp;#39;re ready to start running &lt;code&gt;git bisect&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Finding the bad commit with bisect&lt;/h3&gt;

&lt;p&gt;From the &lt;code&gt;components-ember&lt;/code&gt; folder start with running the &lt;code&gt;git bisect start&lt;/code&gt; command, this will start your bisect session. Then run &lt;code&gt;git bisect bad&lt;/code&gt; to tell the bisect session that the current commit is a bad commit. The next step is a little bit harder, you will need to find a commit that you are sure of to be good. One trick is to go back about six weeks (about one Ember version) in the history and pick a commit, this commit will have a high chance of being good. One warning though: going back too far might cause you to find a bug that is irrelevant to your case. When you have found such a commit, run &lt;code&gt;git bisect good &amp;lt;sha-of-good-commit&amp;gt;&lt;/code&gt;. The response will look something like the following:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Bisecting: 117 revisions left to test after this (roughly 7 steps)
[4e1224de1687a86dc83936e880104b6b1a48bbe2] Ember Bower Auto build for https://github.com/emberjs/ember.js/commits/d2b56a290a45b23a792575dfa6e3af37cf58bc79.
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This means that there are 117 commits left that can contain the commit you are looking for, and that it will take about 7 more steps to find it.&lt;/p&gt;

&lt;p&gt;You should now notice that bisect has moved the &lt;code&gt;components-ember&lt;/code&gt; repository to a different commit somewhere between your initial good and bad commits. In this case it is &lt;code&gt;4e1224de1687a86dc83936e880104b6b1a48bbe2&lt;/code&gt; This is the first commit bisect has selected to test. It will wait for you to report if this commit is good or bad.&lt;/p&gt;

&lt;p&gt;Now go back to your app&amp;#39;s folder and run your tests (&lt;code&gt;ember test&lt;/code&gt; for example). If all tests pass the suggested commit must be a good commit, run &lt;code&gt;git bisect good&lt;/code&gt; in the &lt;code&gt;components-ember&lt;/code&gt; folder to tell the bisect process that this commit is a good commit. If the tests fail, then run &lt;code&gt;git bisect bad&lt;/code&gt; to tell the bisect process that this commit is a bad one.&lt;/p&gt;

&lt;p&gt;After having specified if the commit is either good or bad bisect will respond with a similar message:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Bisecting: 58 revisions left to test after this (roughly 6 steps)
[73f02564972bbd14a719f707af019d94c822939c] Ember Bower Auto build for https://github.com/emberjs/ember.js/commits/1be0354068d933065ac542f49d42d73409366a47.
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With this step it has eliminated 59 commits, and there are only 58 commits left that can contain the commit you are looking for. It has also moved the &lt;code&gt;components-ember&lt;/code&gt; repository to the next commit that it needs you to test if it&amp;#39;s good or bad.&lt;/p&gt;

&lt;p&gt;Run your app&amp;#39;s tests again and either run &lt;code&gt;git bisect good&lt;/code&gt; or &lt;code&gt;git bisect bad&lt;/code&gt; based on the results of the tests.&lt;/p&gt;

&lt;p&gt;Keep repeating this process until it reports the bad commit:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;9f6b98391523c4be437e1f6cd1a5956e69ecc0a9 is the first bad commit
commit 9f6b98391523c4be437e1f6cd1a5956e69ecc0a9
Author: Tomster &amp;lt;tomster@emberjs.com&amp;gt;
Date:   Sat Jun 11 00:03:22 2016 +0000

    Ember Bower Auto build for https://github.com/emberjs/ember.js/commits/b44f9dad912a73668dda142c34a6858283003403.
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Congratulations! You have found the bad commit that introduced the bug that you were looking for. In this case it&amp;#39;s &lt;code&gt;9f6b98391523c4be437e1f6cd1a5956e69ecc0a9&lt;/code&gt;, and luckily the commit message includes the commit the build is from, so you can go to the GitHub url from the commit message and see the original commit.&lt;/p&gt;

&lt;h3&gt;What if I wrongly report a commit as bad or good?&lt;/h3&gt;

&lt;p&gt;Unfortunately, bisect has no undo command, so you will have to start from the top again. To do this first run &lt;code&gt;git bisect reset&lt;/code&gt;, this will end your bisect session. Now you can start over by running &lt;code&gt;git bisect start&lt;/code&gt; and then marking a good and bad commit, which then will start the iterative process of marking commits selected by bisect good or bad again.&lt;/p&gt;

&lt;h3&gt;Can I automate this a little bit more?&lt;/h3&gt;

&lt;p&gt;Yes you can! Bisect has the command &lt;code&gt;git bisect run&lt;/code&gt;, which will run a command for you on each iteration. If the command succeeds it will mark the commit as good, if the command fails it will mark the commit as bad.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s take a look at how to do this with our example.&lt;/p&gt;

&lt;p&gt;To reliably run the tests each iteration I added the following bash script to the &lt;code&gt;components-ember&lt;/code&gt; folder, I called it &lt;code&gt;ember-bisect-test.sh&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;#!/bin/sh

cd &amp;lt;path/to/your/project/folder&amp;gt;
rm -rf bower_components/ember
bower link ember
ember test
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Mark the file as executable:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;chmod +x ember-bisect-test.sh
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And now we can let bisect run your script on each iteration:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;git bisect run ./ember-bisect-test.sh
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;What have we learned?&lt;/h3&gt;

&lt;p&gt;You have now learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The basics of how &lt;code&gt;git bisect&lt;/code&gt; works.&lt;/li&gt;
&lt;li&gt;How to use &lt;code&gt;git bisect&lt;/code&gt; with the Ember.js canary channel to track down commits that introduce regressions.&lt;/li&gt;
&lt;li&gt;How to restart the process when you mess it up.&lt;/li&gt;
&lt;li&gt;How to automate &lt;code&gt;git bisect&lt;/code&gt; with a script.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry><entry>
    <title>Productive debugging</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/07/26/debugging-ember-tests" />
    <id>https://dockyard.com/blog/2016/07/26/debugging-ember-tests</id>
    
    <published>2016-07-26 00:00:00</published>
    <updated>2016-07-28 15:11:49</updated>
    <author><name>Romina Vargas</name></author>
    <summary>A peek into different debugging methods</summary>
    <content type="html">&lt;p&gt;If you attended &lt;a href=&quot;https://wickedgoodember.com/&quot;&gt;Wicked Good Ember&lt;/a&gt; this past June,
it quickly became apparent that it was a Test Driven Conference - three
testing-related talks happened to be grouped together at the start of the
conference. It&amp;#39;s clear that Ember developers care about testing. In fact, there
is an open &lt;a href=&quot;https://github.com/rwjblue/rfcs/blob/42/text/0000-grand-testing-unification.md&quot;&gt;RFC&lt;/a&gt;
to unify the way Ember does testing. I highly recommend reading it! Currently,
there are three different ways to test; one for each of the different types of
tests: unit, integration, and acceptance. However, while the unification becomes
reality, we must keep testing as usual, and I&amp;#39;d like to go over some quick tips
for debugging in the different test environments!&lt;/p&gt;

&lt;h2&gt;pauseTest();&lt;/h2&gt;

&lt;p&gt;This first function is acceptance test specific, but according to the RFC, it
will eventually become available to use in all types of tests. When writing
tests, it&amp;#39;s helpful to be able to inspect the state of the DOM. Inserting a
call to &lt;code&gt;pauseTest()&lt;/code&gt; inside an acceptance test will pause the test suite at
the point that it sees the function call. This allows for developer interaction
with the current state of the application. Internally, &lt;code&gt;pauseTest()&lt;/code&gt; returns a
promise that will never resolve.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I can submit the contact form&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(&lt;span class=&quot;comment&quot;&gt;/*assert*/&lt;/span&gt;) {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/contact-form&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; pauseTest();

  &lt;span class=&quot;comment&quot;&gt;// failing interaction&lt;/span&gt;
  click(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;button:contains(&amp;quot;Submit&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After running the above test on the browser, the test suite would pause once it
reaches L3. The application would be viewable exactly as it appears before
the &lt;code&gt;click&lt;/code&gt; takes place.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example use case:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I want to click the &amp;quot;Submit&amp;quot; button but my test is not finding that element,
therefore, it&amp;#39;s failing. With &lt;code&gt;return pauseTest()&lt;/code&gt;, I&amp;#39;m able to see that I&amp;#39;m not
actually in the expected &lt;code&gt;/contact-form&lt;/code&gt; route, but that I&amp;#39;m being redirected to
the &lt;code&gt;/login&lt;/code&gt; route. Now I can fix my test by logging in before visiting
&lt;code&gt;/contact-form&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;assert.async();&lt;/h2&gt;

&lt;p&gt;This function is a favorite of mine, and I remember the excited when I first
learned about it a while ago (thanks &lt;a href=&quot;https://twitter.com/martndemus&quot;&gt;Marten&lt;/a&gt;!). The use of
&lt;code&gt;assert.async()&lt;/code&gt; is available to use in both acceptance and integration tests,
but it&amp;#39;s currently the only way to pause an integration test Calling
&lt;code&gt;assert.async()&lt;/code&gt; is similar to &lt;code&gt;pauseTest()&lt;/code&gt;; you can inspect the state of the
DOM and play around with it while the test is paused. It&amp;#39;s a great tool for
integration testing because much of the time, you&amp;#39;re testing that certain
content/element appears on the page as a result of a user interaction. I find
it particularly useful to quickly find &lt;code&gt;class&lt;/code&gt; names, &lt;code&gt;data-auto-id&lt;/code&gt;s, etc,
instead of going back to the templates where they are defined.&lt;/p&gt;

&lt;p&gt;This &lt;a href=&quot;https://api.qunitjs.com/async/&quot;&gt;&lt;code&gt;async()&lt;/code&gt;&lt;/a&gt; method comes for free with Qunit, which is Ember&amp;#39;s
built-in testing framework.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Clicking &amp;quot;Add contact&amp;quot; displays new contact form&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.render(hbs&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;{{contacts users=users}}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
  click(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;button:contains(&amp;quot;Add contact&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  assert.async();

  &lt;span class=&quot;comment&quot;&gt;// failing assertion&lt;/span&gt;
  let form = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[data-auto-id=&amp;quot;new-contact&amp;quot;]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  assert.equal(form.length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;New contact form is displayed&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Like with the &lt;code&gt;pauseTest()&lt;/code&gt; example, once the test runner reaches L5 above,
the test suite will pause and the current state of the DOM can be viewed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example use case:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I want to make sure that my new contact form is displayed on the page. I know
that the functionality is working, but my test is still failing. I can add a
call to &lt;code&gt;assert.async()&lt;/code&gt; to check out the DOM. Turns out I was using the wrong
&lt;code&gt;data-auto-id&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;debugger;&lt;/h2&gt;

&lt;p&gt;No debugging function left behind. There&amp;#39;s no need to explain what &lt;code&gt;debugger;&lt;/code&gt;
does, but when you need to debug some functionality without caring about what
the UI looks like, then you&amp;#39;re good to place a &lt;code&gt;debugger;&lt;/code&gt; call inside any test.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Gotta Catch &#39;em All!</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/07/20/gotta-catch-them-all" />
    <id>https://dockyard.com/blog/2016/07/20/gotta-catch-them-all</id>
    
    <published>2016-07-20 00:00:00</published>
    <updated>2016-08-04 14:32:47</updated>
    <author><name>Romina Vargas</name></author>
    <summary>DockYarders&#39; take on Pokemon GO with some UX flavor</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/vCbmLzz.jpg&quot; alt=&quot;Drowzee&quot;&gt;&lt;/p&gt;

&lt;p&gt;If you haven&amp;#39;t yet heard of Pokemon GO, you might be living under a rock. Or
under an Onyx. Pokemon GO was released on July 7, 2016 in the United States and
it immediately became viral. It&amp;#39;s a mobile application that makes use of the GPS
and camera to bring the user an Augmented Reality experience by allowing them
to catch Pokemon in a real-world environment. The game encourages its users to
go outside and become the &lt;a href=&quot;https://www.youtube.com/watch?v=NcfdoSuC6MI&quot;&gt;Pokemon Masters&lt;/a&gt;
they always dreamed of being, or now dream of being. Talk about nostalgia. Even
if one didn&amp;#39;t grow up with the franchise, the newly-released game is still
revolutionary due to its immersive nature and social aspect. Like much of the
world, most DockYarders have picked up the game and some would like to share
their thoughts and experiences with you!&lt;/p&gt;

&lt;h1&gt;Maria M: Pokemon GO UX Lessons&lt;/h1&gt;

&lt;p&gt;I took four days to experiment casually with the game - and looked over the
shoulder of a few others with a far more serious approach to it. Here&amp;#39;s what I
learned about UX design.&lt;/p&gt;

&lt;h3&gt;11:30pm, near downtown Boston&lt;/h3&gt;

&lt;p&gt;I&amp;#39;m an observer right now, not actively playing. Pleasant summer night in
Boston and a whole lot of people are walking circles around the body of water
near the Christian Science Center - a complex made up of a large cathedral and
an even larger administrative building. Normally, the area is pretty empty at
this hour. Not everyone is staring directly down at their phone screen, but I
can pretty much tell who is playing the game and who is here for other reasons.
The players are all in their 20s, and come from a similar demographic, about
half white and half Asian. (This does not represent what I have seen in Boston
on average, or even in the Boston tech and design scene.)&lt;/p&gt;

&lt;h3&gt;Population&lt;/h3&gt;

&lt;p&gt;Once I got adjusted to the sight of the chill looking crowds gathering in spaces
that are normally emptier, I realize what looks âoffâ about the situation. Itâs
the feeling I might get on a college campus tour, when everyoneâs around my age.
I am guessing the earliest adopters of Pokemon GO very clearly the people of more
access to games and the Internet and technology in general. I spot just one
family with a stroller - and they stand out. I realize that just being able to
gather here unencumbered by 6am school drop-offs, caring for a family, or working
several jobs represents privilege and access to leisure that not everyone has.&lt;/p&gt;

&lt;p&gt;I think this reveals that we often end up designing for folks just like us. Early
adopters of the Pokemon GO are probably similar to the first users who sign up for
many web apps, and even though we assume we&amp;#39;re making something that&amp;#39;s good for
the âgeneral publicâ weâre often actually catering only to ourselves.&lt;/p&gt;

&lt;h3&gt;The space&lt;/h3&gt;

&lt;p&gt;Obviously one of the reasons that the game is so addicting is that it uses 3-D
space to play the game. You physically have to be close to an object to claimant
in the game and geolocation is playing a major role in making that happen. The
game is designed for walking on foot but sometimes you can cheat a little bit and
for example the on the bike or claim some of the objects from a public bus. But
in either case I found that I&amp;#39;ve learned remarkably well after just a few attempts
exactly how close I have to be physically to a marks location in order to claim it.
I think this is especially interesting because before this I had a general sense
of how accurate things like GPS and Wi-Fi are to locate me in 3-D space but now I
have a physical sense in my body exactly how far I need to walk to or from the
corner to be within reach of a specific object on the 3-D map. If nothing else,
the game will vastly improve our understanding of the accuracy of GPS and Wi-Fi
location tracking.&lt;/p&gt;

&lt;h3&gt;When a digital experience works, it changes the world&lt;/h3&gt;

&lt;p&gt;The third takeaway for me is a really hopeful one. Obviously I&amp;#39;m not going to be
the only one who says that his game is changing the world. People are not just
sitting or walking staring at their phones by themselves. They are chatting with
other people, yelling out when when they successfully capture rare PokÃ©mon they
really wanted and in general or just smiling at each other. I assume these are
the same people who would normally sit at home by themselves staring at the
personal screen and not talking to anyone. And even though we fight around the
same damn pool of water near the Christian science center about seven times
already, I&amp;#39;m getting a fun romantic evening walk with my s/o, when normally at
this time I would have been staring blankly at my own screen.&lt;/p&gt;

&lt;p&gt;He just informed me that it is midnight and we should probably leave so we could
get home in time to get a little bit asleep before starting work tomorrow. But
overall it was a fairly nice night and he seems happy as well.&lt;/p&gt;

&lt;p&gt;But more importantly, the experience people are having in this park and in many
places in the world right now with this game is not virtual â it&amp;#39;s real. And it
gives me hope because when working for a long time on complex products it&amp;#39;s easy
to get discouraged. When you&amp;#39;re tired, itâs easy to slip into thinking that
whatever you&amp;#39;re making will not make a difference. This game offers us a reminder
for me of real change in the physical world that can happen when an interaction
is built just right.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/anildash/status/753261028801187840&quot;&gt;&lt;em&gt;&amp;quot;Broken tech culture is seeing the success of PokÃ©mon Go &amp;amp; attributing it to AR
instead of a huge 25-year-old global cultural phenomenon.&amp;quot;&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Cory T: Expert user point of view&lt;/h1&gt;

&lt;p&gt;With walking everywhere and following PokemonGoHub on &lt;a href=&quot;https://twitter.com/pokemongohub&quot;&gt;Twitter&lt;/a&gt;,
I have been appointed DockYard Pokemon GO expert! This game has been on my radar
ever since one of the first teasers surfaced online and the nostalgia hits you
like a punch from Rocky Balboa.&lt;/p&gt;

&lt;p&gt;Ten minutes after Pokemon GO was available in the Play Store (thanks Twitter) I
had the game downloaded and caught my first and favorite Pokemon of all time,
Squirtle. After seeing Squirtle in my Pokedex I legitimately felt like I was
back in 4th-6th grade collecting Pokemon cards in my 3-ringed binder. Crazy
thing is I now I have my own freaking Pokedex on my phone with Pokemon I caught
in the real world!&lt;/p&gt;

&lt;p&gt;Nostalgia aside, I might have a different opinion on the UX of the game.&lt;/p&gt;

&lt;p&gt;I like it.&lt;/p&gt;

&lt;p&gt;For example, Pokemon GO doesnât tell you to spin the ball in order to throw curve
balls (this makes it easy to catch rare Pokemon). The mechanics on how to fight a
gym is never explained. How to pick what your Eevee will evolve into is not obvious.&lt;/p&gt;

&lt;p&gt;Does this game tell you how to do anything? No. But, I actually like figuring out
how to play this game - socializing with other people about new tricks they have
found has been great.&lt;/p&gt;

&lt;h3&gt;What I want to see&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Web app that lets me manage my Pokemon online&lt;/li&gt;
&lt;li&gt;Pokemon trading (coming very soon according to Pokemon GO)&lt;/li&gt;
&lt;li&gt;Have the ability to select multiple Pokemon and transfer them to Professor Ashe

&lt;ul&gt;
&lt;li&gt;Currently 3 clicks to transfer a Pokemon&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Currently the game is a grind to find the best version of a specific Pokemon
species, I would rather invest and care for one that I catch and train the Pokemon
new attacks and upgrade its statistics. Will make them more personable and pet-like&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=M6ereCy5qY4&quot;&gt;Pro tip&lt;/a&gt;: If you want to actually
know what your Eevee will evolve into compared to the random selection, give
Eevee the desired nickname. This should work every time unless there is a
bug/glitch. The trainers of Vaporeon, Flareon and Jolteon in episode 40 of the
TV show are the key to this trick:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pyro = Flareon&lt;/li&gt;
&lt;li&gt;Sparky = Jolteon&lt;/li&gt;
&lt;li&gt;Rainer = Vaporeon&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Patrick B: Resister Turned Lover&lt;/h1&gt;

&lt;p&gt;Generally when an audience as large as...well...seemingly the entire world...takes
notice of an application, game or service, I start my relationship with said
application, game or service with resistance. Not because I donât want to involve
myself but because I want to witness the reactions of others. Iâm not judging
people using it. Iâm observing people using it. Eventually I give in (usually
after patch 1 or 2) and then compile my thoughts and assemble my like or dislike
for the application, game or service.&lt;/p&gt;

&lt;p&gt;This process has never been harder than with Pokemon GO. Perhaps itâs because no
application for a mobile device has become this popular this quickly. Perhaps itâs
because I love(d) Pokemon and donât want to tarnish my grand memories of the
franchise. Perhaps itâs because...it wouldnât install the first few attempts.&lt;/p&gt;

&lt;p&gt;I resisted hard at the beginning. One week later, Iâm level 13 and furiously
collecting as many Pokemon as I can. I love it as much as I hoped I would. I love
it as a designer. I love it as a casual fan of Pokemon. I love it as a heavy gamer.
My mother loves it. My brother loves it. My cousin loves it. None of them design,
game or were ever engulfed in the world of Pokemon.&lt;/p&gt;

&lt;p&gt;At the very least, you should try Pokemon GO. Perhaps youâll love it too. Here are
four reasons why in one week you just might find yourself taking notice to the game
everyoneâs talking about:&lt;/p&gt;

&lt;h3&gt;Nostalgia&lt;/h3&gt;

&lt;p&gt;If you were at all in tune with video games through the 90s and 00s, youâre
inevitably familiar with at least the name âPokemon.â However if youâre familiar
with the name, you likely fell hard in love to some degree with the Pokemon empire
(whether youâd like to admit it or not). If you traded, collected or sold the
cards youâre very likely to enjoy this game. If you were consumed by the colored
Gameboy games youâre very likely to enjoy this game. If you dreamt of the Snap or
Stadium realms being real environments for you to roam and interact with beyond
the 64 joystick youâre very likely to enjoy this game. If youâve lived by Nintendo
platforms in general youâre very likely to enjoy this game. What once was a game
then became an empire. That empire is now an entire world.&lt;/p&gt;

&lt;h3&gt;We Love Collecting&lt;/h3&gt;

&lt;p&gt;While it remains a strange compulsion, itâs no secret that people like to collect
things. Cars, video games, sports memorabilia, sneakers, art, you name it and there
are people who focus on collecting as much of it as they can. Thereâs an addictive
pleasure to finding something that may have been lost or perhaps evaded us for
some time. Dating back to the Victorians, the act of collecting items has been a
consistent habit driven by both necessity and desire. The entire Pokemon franchise
is heavily built on this addictive action. Itâs why we see their playing cards sold
for thousands of dollars. Itâs why an entire video game can be built around simply
discovering and photographing objects. And itâs partially why people are taking
time to feverishly compile libraries of Pokemon in their Pokedex sometimes entirely
omitting from their play the many other aspects of the game. The idea of collection
is built directly into their brand. You just âgotta catch them all!â Itâs a
challenge we secretly love.&lt;/p&gt;

&lt;h3&gt;Augmented Reality&lt;/h3&gt;

&lt;p&gt;While VR (virtual reality) is undoubtedly all the rage, thereâs something to be
said about AR (augmented reality). Letâs look at it in the context of Pokemon
GO: It can be created without extra hardware, itâs portable in that itâs reliant
on a mobile device, it doesnât cost much, and it fuses fictional subjects with
the reality of your environment â an actual, unprogrammed, environment. VR,
while amazing in its own right for so many reasons, relies on those things AR
doesnât. This isnât to say Pokemon GO is popular because of its emphasis on AR,
but it proves that an AR driven experience can still be immensely successful.
Before we strap on our head gear, what opportunities can this success story shed
light on?&lt;/p&gt;

&lt;h3&gt;UX Exposure&lt;/h3&gt;

&lt;p&gt;Itâs not a secret that the Pokemon GO application has kinks. On an average day,
I have to close and restart the application several times do to it freezing or
completely crashing. Do I care? No because Iâm addicted. When I installed Pokemon
GO it failed to install, and then failed to create my account two times. In fact
I uninstalled it for a day I was so frustrated. But here I am a week later using
it. As a visual designer in a UX word, this exposure to conflicts and failures
has actually caught my attention, mostly because Iâve forced myself to experience
them knowing the payoff will be worth it. Itâs allowed me to take notice of how
the visuals handle failures on the server side. Itâs allowed me to take notice
of my behaviors when failures do happen. Do I wait to close the app? How long do
I wait? When do I notice itâs not working correctly? How is this represented by
the field of view? Is the AR functionality instigating it? Because Iâve
experienced the pleasure of playing, and am willing to suffer to an extent, Iâve
allowed myself to be content with its failures so much so that itâs begun to
provide me insight into aspects of the actual application I may not have given
the time to. Maybe itâll result in a useless collection of observations. But
maybe itâll result in my paying attention to these aspects more so in the next
project Iâm involved in. Nevertheless, itâs a remarkable feat to be so successful
yet still provide so many instances of frustration unrelated to the game itself.&lt;/p&gt;
</content>
  </entry><entry>
    <title>DockYard Expands To San Diego</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/07/05/dockyard-expands-to-san-diego" />
    <id>https://dockyard.com/blog/2016/07/05/dockyard-expands-to-san-diego</id>
    
    <published>2016-07-05 00:00:00</published>
    <updated>2016-07-28 15:11:49</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Coast to coast</summary>
    <content type="html">&lt;p&gt;For almost two years I&amp;#39;ve been talking a big game inside DockYard about
opening a San Diego office. The need for this became more apparent after
the winter of early 2015 in Boston. Try recruiting anyone to move to
Boston after hearing about nearly 20 ft of snow being dumped on the
city. So I figured we&amp;#39;ll open an office in the nicest place in America.&lt;/p&gt;

&lt;p&gt;Having a San Diego office gives us a West Coast presence. Heading up
this effort we&amp;#39;ve hired &lt;a href=&quot;https://twitter.com/caligoanimus&quot;&gt;Heather Brysiewicz&lt;/a&gt;. She&amp;#39;s been heavily involved
with the tech community in San Diego for a few years now, running the &lt;a href=&quot;http://www.meetup.com/sandiegojs/&quot;&gt;SD
JS meetup&lt;/a&gt; and founding the &lt;a href=&quot;http://www.meetup.com/sandiego-ember/&quot;&gt;SD Ember meetup&lt;/a&gt;. She recently started
co-organizing the &lt;a href=&quot;http://www.meetup.com/San-Diego-Elixir-Erlang/&quot;&gt;SD Elixir meetup&lt;/a&gt;. On top of that she&amp;#39;s an amazing
engineer.&lt;/p&gt;

&lt;p&gt;We&amp;#39;re beginning to explore other locations as well. As we continue to
grow some of our existing employees have expressed interest in leaving
Boston. Until recently we held a &amp;quot;Boston-only&amp;quot; policy but over the past six
months we&amp;#39;ve been experimenting with changing this. Our reluctance lay
within managing client projects with remote devs properly and exporting
our culture. Our team has been working hard to codify many of the
aspects of what it means to work at DockYard but also work with
DockYard. We&amp;#39;ve come to a good comfort level with remote developers 
and the idea of other &amp;quot;DockYard&amp;quot;s outside of Boston.&lt;/p&gt;

&lt;p&gt;Starting today we&amp;#39;re now accepting contracts and offering on-site
training for Ember.js and Elixir for the West Coast. &lt;a
href=&quot;https:/dockyard.com/contact&quot;&gt;If you have a
project in mind please get in touch!&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Personal Growth Cycle: Learning How To Learn</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/07/01/cycle-of-growth" />
    <id>https://dockyard.com/blog/2016/07/01/cycle-of-growth</id>
    
    <published>2016-07-01 00:00:00</published>
    <updated>2016-07-01 08:26:37</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Learning a skill is rewarding, but learning how to learn is even more so.</summary>
    <content type="html">&lt;p&gt;For the longest time, I&amp;#39;ve felt like an imposter in the ever-increasingly complex world that is the tech industry. New terminology and best practices emerge every other day at a relentless pace. Frameworks come and go, new ideas become standard, and thought-leaders discover that &lt;em&gt;yet another thing&lt;/em&gt; is considered harmful.&lt;/p&gt;

&lt;p&gt;With an intense culture unlike any other, it&amp;#39;s no surprise that feelings of inadequacy are commonplace. Prior to joining DockYard, I was just another Australian developer enjoying internet anonymity. The &lt;a href=&quot;https://everperform.com/&quot;&gt;startup&lt;/a&gt; I worked with (2014) then used Ember on the front-end, and my colleagues and I found it difficult to work with. This was prior to Ember 1.13, so things were a lot different back then!&lt;/p&gt;

&lt;h2&gt;The first step is admitting it&lt;/h2&gt;

&lt;p&gt;I started my &lt;a href=&quot;https://medium.com/@sugarpirate/&quot;&gt;blog&lt;/a&gt; during that time, mostly writing about &amp;quot;cool&amp;quot; things we had done with Ember like drag and drop, flash messages, and so on. I didn&amp;#39;t think too much of it then. After all, I was still considered relatively junior, it being my first real job outside of my &lt;a href=&quot;http://www.thepricegeek.com/&quot;&gt;own startup&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Starting out as a self-taught designer, I learnt front-end development while working on my startup, and in my time at my first job. Coding was unlike anything I had ever done before, but I loved it, and kept at it even when I was frustrated.&lt;/p&gt;

&lt;p&gt;My writing was a way to document (and learn from) how I tried to solve a particular problem. To my surprise, some of the more prominent members of the Ember community started to take notice, and I was asked to try my hand at submitting a talk to &lt;a href=&quot;http://2015.emberconf.com/&quot;&gt;EmberConf&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;Get out of your comfort zone&lt;/h2&gt;

&lt;p&gt;Public speaking was (and still is) my greatest fear, so it took a little convincing before I decided I would try submitting a proposal. My talk ended up being accepted, and despite being absolutely terrified, I walked up on stage facing hundreds of people, and &lt;a href=&quot;https://www.youtube.com/watch?v=TlU0m18Pr-Y&quot;&gt;delivered the talk&lt;/a&gt; I had prepared so hard for.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/bcardarella&quot;&gt;Brian&lt;/a&gt; reached out to me shortly after, and I joined DockYard in March last year. He saw the potential in me I couldn&amp;#39;t, and in the past year or so, I&amp;#39;ve grown in many ways. There are amazing people here who constantly push you to become better, and it&amp;#39;s no exaggeration when I say that DockYard is one of the best places I&amp;#39;ve been fortunate enough to work at.&lt;/p&gt;

&lt;p&gt;When I first started, I was &lt;a href=&quot;https://gds.blog.gov.uk/2016/05/25/its-ok-to-say-whats-ok/&quot;&gt;terrified&lt;/a&gt;. I didn&amp;#39;t think I could do it, because I had little experience. Despite that fear, I kept at it â things started making sense, and I could even explain to others. &lt;/p&gt;

&lt;p&gt;This year, I worked solo on a project for a client â an API built using Elixir / Phoenix. I was terrified, again. I didn&amp;#39;t think I could do it, because I had only read a book and wrote a tiny bit of Elixir. Despite that fear, I kept at it â things started making sense, and now I&amp;#39;m a self-taught full stack developer.&lt;/p&gt;

&lt;h2&gt;The cycle of growth&lt;/h2&gt;

&lt;p&gt;I&amp;#39;m not going to tell you that getting good at something takes 10,000 hours, but it does take time and effort. Learning a new skill or improving one is rewarding, but &lt;em&gt;learning to learn&lt;/em&gt; will reward you many times over.&lt;/p&gt;

&lt;p&gt;Unfortunately, I can&amp;#39;t teach you how to learn. Everyone learns differently, and you must discover it for yourself. What I can tell you, is that &lt;em&gt;how&lt;/em&gt; you learn (visual, experiential, etc) is merely an implementation detail. What&amp;#39;s important is the cycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reflect â Know where you stand&lt;/li&gt;
&lt;li&gt;Do â Get out of your comfort zone&lt;/li&gt;
&lt;li&gt;Learn â Fail and try again&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you&amp;#39;re familiar with the &lt;a href=&quot;http://theleanstartup.com/&quot;&gt;Lean Startup&lt;/a&gt;, you&amp;#39;ll notice that the steps are the same. The cycle is your real world &lt;a href=&quot;https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop&quot;&gt;REPL&lt;/a&gt;, and just like programming, is an excellent way to take a more exploratory approach to learning.&lt;/p&gt;

&lt;h2&gt;Help someone else to grow&lt;/h2&gt;

&lt;p&gt;When you find yourself in a position to mentor, embrace it. Although the cycle is personally rewarding, being able to help someone else to &amp;quot;learn how to learn&amp;quot; is even more so. &lt;/p&gt;

&lt;p&gt;It&amp;#39;s bittersweet, but this month will be my last month working with this amazing team. DockYard has been the perfect environment to put this in practice, and I am eternally grateful that I had the chance to be a part of something special. &lt;/p&gt;

&lt;p&gt;Here&amp;#39;s to more growth!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Component Dependency Injection for Testing In Ember.js</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/06/28/component-dependency-injection" />
    <id>https://dockyard.com/blog/2016/06/28/component-dependency-injection</id>
    
    <published>2016-06-28 00:00:00</published>
    <updated>2016-07-01 08:26:37</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Dependency injection is a useful technique for decoupling parent components from its children.</summary>
    <content type="html">&lt;p&gt;The &lt;a href=&quot;http://martinfowler.com/articles/injection.html&quot;&gt;Dependency Injection&lt;/a&gt; (DI) pattern is a subset of &lt;a href=&quot;http://martinfowler.com/articles/injection.html#InversionOfControl&quot;&gt;Inversion of Control&lt;/a&gt;, and is a useful technique for decoupling the creation of a dependency from the object itself. Don&amp;#39;t let the terminology scare you though! DI is really just &lt;a href=&quot;http://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html&quot;&gt;giving an object its instance variables&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;For example, below is a simple example of the &lt;code&gt;Player&lt;/code&gt; class being implicitly coupled to the &lt;code&gt;Bag&lt;/code&gt; class. The &lt;code&gt;Player&lt;/code&gt; is responsible for creating the dependent objects.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;reserved&quot;&gt;class&lt;/span&gt; Player {
  constructor() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.inventory = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Bag({ &lt;span class=&quot;comment&quot;&gt;/* ... */&lt;/span&gt; });
  }

  add(item) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.inventory.add(item);
  }
}

let bob = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Player();
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Although the example is simple, it&amp;#39;s fairly easy to see that this implementation could be difficult to test in isolation, as you now need to know about the &lt;code&gt;Bag&lt;/code&gt; class in the &lt;code&gt;Player&lt;/code&gt; class&amp;#39; test. DI can help us here:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;reserved&quot;&gt;class&lt;/span&gt; Player {
  constructor({ storageObject }) {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.inventory = storageObject;
  }

  add(item) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.inventory.add(item);
  }
}

let bob = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Player({ &lt;span class=&quot;key&quot;&gt;storageObject&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Bag({ &lt;span class=&quot;comment&quot;&gt;/* ... */&lt;/span&gt; }));
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the second example, we &amp;quot;inverted control&amp;quot; of the player&amp;#39;s inventory, and now we pass the storage object instance at runtime. This means that in our test, we can simply stub the inventory object out:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;it adds an item&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  let dummyStorage = { &lt;span class=&quot;comment&quot;&gt;/* ... */&lt;/span&gt; };
  let dummy = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Player({ &lt;span class=&quot;key&quot;&gt;storageObject&lt;/span&gt;: dummyStorage });

  assert.ok(&lt;span class=&quot;comment&quot;&gt;/* ... */&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Player&lt;/code&gt; class no longer needs to know anything about the &lt;code&gt;Bag&lt;/code&gt;, and also allows other kinds of storage object classes to be used. Great!&lt;/p&gt;

&lt;h2&gt;Component Dependency Injection&lt;/h2&gt;

&lt;p&gt;I recently realized that the DI pattern can also be used to great effect in Ember components. For example, let&amp;#39;s say you have a container or parent component that uses multiple child components:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;!-- templates/application.hbs --&amp;gt;

{{edit-location location=location}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;!-- components/edit-location.hbs --&amp;gt;

{{google-map 
    lat=location.lat 
    lng=location.lng 
    setLatLng=(action &amp;quot;setLatLng&amp;quot;)
    setMarkerRadius=(action &amp;quot;setMarkerRadius&amp;quot;)
}}
{{edit-location-form location=location}}
{{location-activity location=location}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The parent component &lt;code&gt;edit-location&lt;/code&gt;&amp;#39;s primary responsibility is to provide UI to edit a location. It could have actions defined on it, like so:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// components/edit-location.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    setLatLng(latLng) {
      &lt;span class=&quot;comment&quot;&gt;// logic&lt;/span&gt;
    },

    setMarkerRadius(radius) {
      &lt;span class=&quot;comment&quot;&gt;// logic&lt;/span&gt;
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;google-map&lt;/code&gt; component provides UI for the user to drop a marker on a map, and adjust the radius around the marker by using the radius control. Needless to say, that UI interaction is quite difficult to test, and is tested in the &lt;code&gt;google-map&lt;/code&gt; component test itself. Because the &lt;code&gt;edit-location&lt;/code&gt; component is tightly coupled to its child components, testing it is no easy task. We need to make sure all the child components are setup just right, which introduces a lot of boilerplate in our component integration test.&lt;/p&gt;

&lt;h2&gt;Not my concern&lt;/h2&gt;

&lt;p&gt;In this scenario, the &lt;code&gt;edit-location&lt;/code&gt; component itself shouldn&amp;#39;t need to concern itself with &lt;em&gt;how&lt;/em&gt; the &lt;code&gt;latLng&lt;/code&gt; and &lt;code&gt;radius&lt;/code&gt; arguments are passed into its actions. The drag and drop UI is a concern of the &lt;code&gt;google-map&lt;/code&gt; component, and as such should be tested in its own component integration test.&lt;/p&gt;

&lt;p&gt;Using DI, we can decouple the &lt;code&gt;edit-location&lt;/code&gt; component from its child components, and clean up our tests. This technique is currently only possible with &lt;a href=&quot;http://emberjs.com/blog/2016/01/15/ember-2-3-released.html#toc_contextual-components&quot;&gt;contextual components&lt;/a&gt; due to the use of the &lt;code&gt;component&lt;/code&gt; and &lt;code&gt;hash&lt;/code&gt; helpers, which were made available in &lt;a href=&quot;http://emberjs.com/blog/2016/01/15/ember-2-3-released.html&quot;&gt;Ember 2.3.0&lt;/a&gt;. &lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;!-- application.hbs --&amp;gt;

{{edit-location 
    location=location
    ui=(hash
      location-map=(component &amp;quot;google-map&amp;quot;)
      location-form=(component &amp;quot;edit-location-form&amp;quot;)
      location-activity=(component &amp;quot;location-activity&amp;quot;))
}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We&amp;#39;ve passed in a hash of the child components using the &lt;code&gt;hash&lt;/code&gt; and &lt;code&gt;component&lt;/code&gt; helpers. This effectively inverts control to the template that calls the &lt;code&gt;edit-location&lt;/code&gt; form:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;!-- components/edit-location.hbs --&amp;gt;

{{ui.location-map 
    lat=location.lat 
    lng=location.lng 
    setLatLng=(action &amp;quot;setLatLng&amp;quot;)
    setMarkerRadius=(action &amp;quot;setMarkerRadius&amp;quot;)
}}
{{ui.location-form location=location}}
{{ui.location-activity location=location}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, in our tests, we&amp;#39;ll need to write a little test helper to create a dummy component we can use to no-op (do nothing). Credit goes to &lt;a href=&quot;https://twitter.com/runspired&quot;&gt;@runspired&lt;/a&gt; for nudging me in the right direction:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// tests/helpers/dummy-component.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  Component,
  assign,
  getOwner
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;registerDummyComponent&lt;/span&gt;(context, name = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dummy-component&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, opts = {}) {
  let owner = getOwner(context);
  let options = assign({ &lt;span class=&quot;key&quot;&gt;tagName&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dummy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }, opts);
  let DummyComponent = Component.extend(options);

  unregisterDummyComponent(context);
  owner.register(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;component:&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{name}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;, DummyComponent);
}

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;unregisterDummyComponent&lt;/span&gt;(context, name = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dummy-component&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) {
  let owner = getOwner(context);

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (owner.resolveRegistration(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;component:&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{name}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;)) {
    owner.unregister(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;component:&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{name}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This test helper registers a fake component in the container, making it available for us to use in our component integration test:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// tests/integration/edit-location-test.js&lt;/span&gt;

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;it ...&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  registerDummyComponent(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {});
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.render(hbs&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;
    {{edit-location
        location=location
        ui=(hash
          location-map=(component &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dummy-component&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
          location-form=(component &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dummy-component&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
          location-activity=(component &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dummy-component&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))
    }}
  &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);

  assert.ok(&lt;span class=&quot;comment&quot;&gt;/* ... */&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we can test the &lt;code&gt;edit-location&lt;/code&gt; component itself without worrying about setting up child components. That said, DI still allows us to test those child components integrating with &lt;code&gt;edit-location&lt;/code&gt;, in a more controlled environment:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// tests/integration/edit-location-test.js&lt;/span&gt;

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;it updates location via the form&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  registerDummyComponent(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {});
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.render(hbs&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;
    {{edit-location
        location=location
        ui=(hash
          location-map=(component &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dummy-component&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
          location-form=(component &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;edit-location-form&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
          location-activity=(component &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dummy-component&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))
    }}
  &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);

  assert.ok(&lt;span class=&quot;comment&quot;&gt;/* ... */&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I hope you find this useful! It&amp;#39;s not a silver bullet by any stretch, but DI can help you write better isolated components and simplify your tests.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Bringing Ecto Changesets into Ember.js</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/06/17/ember-changeset" />
    <id>https://dockyard.com/blog/2016/06/17/ember-changeset</id>
    
    <published>2016-06-17 00:00:00</published>
    <updated>2016-07-01 08:26:37</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Changesets in Ecto are composable and allow casting and validation when manipulating models. We brought this concept over into Ember.js, which makes dealing with complex forms a cinch.</summary>
    <content type="html">&lt;p&gt;The past month or so, I&amp;#39;ve been working on an &lt;a href=&quot;http://elixir-lang.org/&quot;&gt;Elixir&lt;/a&gt; and &lt;a href=&quot;http://www.phoenixframework.org/&quot;&gt;Phoenix&lt;/a&gt; API for a client. I am blown away by how nice it is working with Elixir and functional programming (FP) concepts. FP feels more intuitive and less prone to &amp;quot;shoot yourself in the foot&amp;quot; scenarios compared to OOP. In fact, I try to use functional approaches wherever possible in JavaScript as well.&lt;/p&gt;

&lt;p&gt;That isn&amp;#39;t to say that one is better than the other, but in my experience less unexpected behavior occurs in FP. It turns out whole classes of bugs disappear when embracing immutability and pure functions.&lt;/p&gt;

&lt;h2&gt;Ecto Changesets to the Rescue&lt;/h2&gt;

&lt;p&gt;In Elixir, we use &lt;a href=&quot;https://github.com/elixir-ecto/ecto&quot;&gt;Ecto&lt;/a&gt;, a DSL for writing queries and interacting with databases. One of the core concepts in Ecto is the &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html&quot;&gt;changeset&lt;/a&gt; â an atomic collection of changes. Changes are validated and checked against database constraints (such as uniqueness) before casting. This ensures that we catch invalid data in the app layer before insertion into the database. Ecto is often confused with &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt;&amp;#39; &lt;a href=&quot;http://guides.rubyonrails.org/active_record_basics.html&quot;&gt;ActiveRecord&lt;/a&gt;, but it isn&amp;#39;t an ORM, and shouldn&amp;#39;t be used like one.&lt;/p&gt;

&lt;p&gt;The idea for bringing changesets into Ember occurred to me while I was working on a new client app. An edit page featured 3 forms, all bound to the same model. Each hidden form had separate &amp;quot;toggle&amp;quot;, &amp;quot;save&amp;quot; and &amp;quot;reset&amp;quot; actions. Using &lt;a href=&quot;https://github.com/martndemus/ember-form-for&quot;&gt;&lt;code&gt;ember-form-for&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/offirgolan/ember-cp-validations&quot;&gt;&lt;code&gt;ember-cp-validations&lt;/code&gt;&lt;/a&gt;, this turned out to be harder than I thought. Editing one form would immediately update the model with 2-way bindings. This was a poor user experience, since you might edit more than 1 form at a time, but want to separate saves and resets.&lt;/p&gt;

&lt;h2&gt;Changesets in Ember&lt;/h2&gt;

&lt;p&gt;In my mind, I could see a solution using changesets. Each form would have a separate changeset, so changes (and validations) would be independent. It turns out that this approach works really well, and I&amp;#39;m happy to announce that you can install it today as an addon with:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ember install ember-changeset
ember install ember-changeset-validations
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I wrote the addon with compatibility in mind, so it&amp;#39;s easy to wire up with your favorite validation library. The simplest way to incorporate validations is to use &lt;a href=&quot;https://github.com/poteto/ember-changeset-validations/&quot;&gt;ember-changeset-validations&lt;/a&gt;, a companion addon. It has a simple mental model, and there are no observers or CPs involved â just pure, plain JavaScript functions.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s take a look at &lt;a href=&quot;https://github.com/poteto/ember-changeset&quot;&gt;&lt;code&gt;ember-changeset&lt;/code&gt;&lt;/a&gt; is implemented, and we&amp;#39;ll also demonstrate how they align with Ember&amp;#39;s &lt;a href=&quot;https://dockyard.com/blog/2015/10/14/best-practices-data-down-actions-up&quot;&gt;Data Down Actions Up&lt;/a&gt; (DDAU) philosophy.&lt;/p&gt;

&lt;h2&gt;Virtual Properties with &lt;code&gt;unknownProperty&lt;/code&gt; and &lt;code&gt;setUnknownProperty&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The core concept behind &lt;code&gt;ember-changeset&lt;/code&gt; is the definition of &lt;code&gt;unknownProperty&lt;/code&gt; and &lt;code&gt;setUnknownProperty&lt;/code&gt;. These methods are invoked (if present) in &lt;code&gt;Ember.get&lt;/code&gt; or &lt;code&gt;Ember.set&lt;/code&gt; whenever an Ember Object does not define a property. Ruby developers would be familiar with this behavior via the &lt;code&gt;method_missing&lt;/code&gt; method. A colleague I used to work with wrote an excellent &lt;a href=&quot;https://emberway.io/metaprogramming-in-emberjs-627921395299#.8m07o1i8u&quot;&gt;blog post&lt;/a&gt; on this topic, please check it out if you&amp;#39;re interested in finding out more!&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let Person = EmberObject.extend({
  &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,

  unknownProperty(key) {
    console.log(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;Could not get &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{key}!&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
  },

  setUnknownProperty(key, value) {
    console.log(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;Could not set &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{key} &lt;span class=&quot;keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{value}!&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When a &lt;code&gt;Person&lt;/code&gt; is created, trying to &lt;code&gt;get&lt;/code&gt; or &lt;code&gt;set&lt;/code&gt; a property other than &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; will invoke the &lt;code&gt;unknownProperty&lt;/code&gt; and &lt;code&gt;setUnknownProperty&lt;/code&gt; methods respectively:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let jim = Person.create({ &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Jim&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bob&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; });
jim.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Jim&amp;quot;&lt;/span&gt;
jim.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Could not get fullName!&amp;quot;&lt;/span&gt;
jim.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;integer&quot;&gt;25&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Could not set age with 25!&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;These two methods allow us to &lt;em&gt;proxy&lt;/em&gt; our changeset to the actual model, meaning we can hold back changes but still forward &lt;code&gt;get&lt;/code&gt;s to the model. &lt;/p&gt;

&lt;h2&gt;Storing Changes&lt;/h2&gt;

&lt;p&gt;Our changeset needs a reference to the underlying model, as well as an internal list of changes to be applied. We can set this up in the &lt;code&gt;init&lt;/code&gt; method of our object, which is invoked whenever a new instance is created. &lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;changeset&lt;/span&gt;(obj, validateFn&lt;span class=&quot;comment&quot;&gt;/*, validationMap */&lt;/span&gt;) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; EmberObject.extend({
    init() {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._content = obj;
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._changes = {};
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._errors = {};
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._validator = validateFn;
    }
  });
}

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;reserved&quot;&gt;class&lt;/span&gt; Changeset {
  constructor() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; changeset(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;).create();
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We want to be able to forward &lt;code&gt;get&lt;/code&gt;s to &lt;code&gt;_content&lt;/code&gt;, but hold back &lt;code&gt;set&lt;/code&gt;s on &lt;code&gt;_changes&lt;/code&gt;, and this is easy enough to set up via virtual properties:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  unknownProperty(key) {
    let content = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;_content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; get(content, key);
  },

  setUnknownProperty(key, value) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._validateAndSet(key, value);
  },

  _validateAndSet(key, value) {
    &lt;span class=&quot;comment&quot;&gt;// if valid, set it on `_changes`&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// otherwise set it on `_errors`&lt;/span&gt;
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Since a changeset should only allow valid changes to be set, we validate the change using the &lt;code&gt;validateFn&lt;/code&gt; function that was passed in to the changeset factory. If a change is valid, we add it to the hash of changes in &lt;code&gt;_changes&lt;/code&gt;, and if it&amp;#39;s invalid and returns an error message, we add it to the hash of &lt;code&gt;_errors&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Of course, there are more implementation details than that, but the concept remains unchanged. After defining a simple public API for using changesets, there wasn&amp;#39;t too much more code to add! For example, this is how you would use a changeset:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let changeset = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Changeset(user, validatorFn);
user.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Michael&amp;quot;&lt;/span&gt;
user.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Bolton&amp;quot;&lt;/span&gt;

changeset.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Jim&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
changeset.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
changeset.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isInvalid&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// true&lt;/span&gt;
changeset.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// [{ key: &#39;lastName&#39;, validation: &#39;too short&#39;, value: &#39;B&#39; }]&lt;/span&gt;
changeset.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bob&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
changeset.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// true&lt;/span&gt;

user.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Michael&amp;quot;&lt;/span&gt;
user.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Bolton&amp;quot;&lt;/span&gt;

changeset.save(); &lt;span class=&quot;comment&quot;&gt;// sets and saves valid changes on the user&lt;/span&gt;
user.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Jim&amp;quot;&lt;/span&gt;
user.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Bob&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Rolling back changes, and even merging them, becomes trivial with a changeset: &lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;changeset.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Milton&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
changeset.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isDirty&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// true&lt;/span&gt;
changeset.rollback();
changeset.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isDirty&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// false&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let changesetA = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Changeset(user, validatorFn);
let changesetB = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Changeset(user, validatorFn);
changesetA.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Jim&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
changesetB.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Jimmy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
changesetB.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Fallon&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
let changesetC = changesetA.merge(changesetB);
changesetC.execute();
user.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Jimmy&amp;quot;&lt;/span&gt;
user.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Fallon&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Data Down Actions Up, Not 2-Way Bindings&lt;/h2&gt;

&lt;p&gt;One of the reasons DDAU is so strongly emphasized in Ember 2.x is because it helps us avoid shooting ourselves in the foot with 2-way bindings (2WBs). 2WBs were the &amp;quot;killer feature&amp;quot; of many JavaScript frameworks when they first debuted. As client side applications matured and became more sophisticated, developers realized that 2WBs were more harmful than useful. 2WBs led to instability and difficult debugging in the form of cascading changes, and &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt; was the first library to attempt to solve this problem.&lt;/p&gt;

&lt;p&gt;React&amp;#39;s breakthrough was in the use of a virtual DOM, a representation of the actual DOM as a tree-like data structure. Diffing the changes between the virtual and real DOM paved the way for the complete removal of 2WBs â the application simply re-renders whenever there is a change in value. &lt;/p&gt;

&lt;p&gt;This continues to be a simpler mental model, and just like Elixir (and other functional languages), eliminates a whole class of bugs. DDAU in Ember.js is built upon the same idea, that data should flow one way.&lt;/p&gt;

&lt;p&gt;Using changesets in Ember takes the DDAU philosophy used in rendering into the realm of interacting with client side view models. Instead of 2WBs, changesets allow one way data flow to a model, ensuring that they are always valid, and eliminating a whole class of synchronization headaches.&lt;/p&gt;

&lt;h2&gt;Is This Real Life?&lt;/h2&gt;

&lt;p&gt;When I dropped in &lt;code&gt;ember-changeset&lt;/code&gt; and &lt;code&gt;ember-changeset-validations&lt;/code&gt; into my client app, it instantly clicked with the way I&amp;#39;ve been writing Ember, using DDAU. My complex forms now have independent validations and changes, and I no longer need to worry about saving an unintended change in one form when I submit another. &lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;ember-changeset&lt;/code&gt; can be used directly in place of an ember-data model, using it with a form library like &lt;a href=&quot;https://github.com/martndemus/ember-form-for&quot;&gt;&lt;code&gt;ember-form-for&lt;/code&gt;&lt;/a&gt; is trivial using the &lt;code&gt;changeset&lt;/code&gt; helper:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{dummy-form changeset=(changeset model (action &amp;quot;validate&amp;quot;))}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#form-for changeset as |f|}}
  {{f.text-field &amp;quot;firstName&amp;quot;}}
  {{f.text-field &amp;quot;lastName&amp;quot;}}
  {{f.date-field &amp;quot;birthDate&amp;quot;}}

  {{f.submit &amp;quot;Save&amp;quot;}}
{{/form-for}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Validating Changesets&lt;/h2&gt;

&lt;p&gt;Validation becomes even simpler with changesets. Throughout Ember&amp;#39;s history, we have largely relied on addons like &lt;a href=&quot;https://github.com/DockYard/ember-validations&quot;&gt;&lt;code&gt;ember-validations&lt;/code&gt;&lt;/a&gt; which make extensive use of observers. Newer libraries like &lt;code&gt;ember-cp-validations&lt;/code&gt; use computed properties (CPs) instead, but that still relies on 2WBs. &lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;ember-changeset&lt;/code&gt; and &lt;code&gt;ember-changeset-validations&lt;/code&gt;, you can take a functional approach with validations. A validator function is passed into the changeset, that is invoked whenever a property is set. This validator function then looks up the appropriate validator (say &lt;code&gt;presence&lt;/code&gt; or &lt;code&gt;format&lt;/code&gt;) on the validation map, and returns &lt;code&gt;true&lt;/code&gt; or an error message.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; {
  validatePresence,
  validateLength,
  validateConfirmation,
  validateFormat
} from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-changeset-validations/validators&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; validateCustom from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../validators/custom&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;comment&quot;&gt;// local validator&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; validatePasswordStrength from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../validators/password-strength&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;comment&quot;&gt;// local validator&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: [
    validatePresence(&lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;),
    validateLength({ &lt;span class=&quot;key&quot;&gt;min&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt; })
  ],
  &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;: validatePresence(&lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;age&lt;/span&gt;: validateCustom({ &lt;span class=&quot;key&quot;&gt;foo&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }),
  &lt;span class=&quot;key&quot;&gt;email&lt;/span&gt;: validateFormat({ &lt;span class=&quot;key&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }),
  &lt;span class=&quot;key&quot;&gt;password&lt;/span&gt;: [
    validateLength({ &lt;span class=&quot;key&quot;&gt;min&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;8&lt;/span&gt; }),
    validatePasswordStrength({ &lt;span class=&quot;key&quot;&gt;minScore&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;80&lt;/span&gt; })
  ],
  &lt;span class=&quot;key&quot;&gt;passwordConfirmation&lt;/span&gt;: validateConfirmation({ &lt;span class=&quot;key&quot;&gt;on&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; })
};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A validator like &lt;code&gt;validatePresence&lt;/code&gt; is simply a function that returns a function:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// validators/custom.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;validateCustom&lt;/span&gt;({ foo, bar } = {}) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; (key, newValue, oldValue, changes) =&amp;gt; {
    &lt;span class=&quot;comment&quot;&gt;// validation logic&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// return `true` if valid || error message string if invalid&lt;/span&gt;
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Which is simpler to reason about compared to an OOP implementation that relies on extending base classes and holding on to state. Because validation maps are simply POJOs, composing validators is intuitive:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// validations/user.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; {
  validatePresence,
  validateLength
} from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-changeset-validations/validators&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: validatePresence(&lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;: validatePresence(&lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;)
};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can easily import other validations and combine them using &lt;code&gt;Ember.assign&lt;/code&gt; or &lt;code&gt;Ember.merge&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// validations/adult.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; UserValidations from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;./user&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { validateNumber } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-changeset-validations/validators&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { assign } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; const AdultValidations = {
  &lt;span class=&quot;key&quot;&gt;age&lt;/span&gt;: validateNumber({ &lt;span class=&quot;key&quot;&gt;gt&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;18&lt;/span&gt; })
};

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; assign({}, UserValidations, AdultValidations);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This approach lets you build up validations independent of the model. Ember Data models aren&amp;#39;t 1 to 1 representations of server-side records, they&amp;#39;re View Models. This means we shouldn&amp;#39;t need to validate them the same way we would a server-side model. For example, you might have &lt;code&gt;User&lt;/code&gt; models in your application, and some of these users might have different roles that require different validation. Best of all, we don&amp;#39;t need to use observers or CPs!&lt;/p&gt;

&lt;h2&gt;The Only Constant is Change&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed reading about the concept and implementation of changesets in Ember. DDAU on your models will make your life simpler and your app easier to reason about! Work is still on-going on these addons, so please try them out and let me know if you have any issues or feedback.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Git Init: My First Two Weeks at DockYard</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/06/17/my-first-two-weeks-at-dockyard" />
    <id>https://dockyard.com/blog/2016/06/17/my-first-two-weeks-at-dockyard</id>
    
    <published>2016-06-17 00:00:00</published>
    <updated>2016-07-01 08:26:37</updated>
    <author><name>Rowan Krishnan</name></author>
    <summary>A review of my first two weeks at DockYard.</summary>
    <content type="html">&lt;h2&gt;How I Got Here&lt;/h2&gt;

&lt;p&gt;Two weeks ago I started working as an intern at DockYard - though it feels like Iâve been learning from the employees here long before then. If that sounds a bit confusing, I can explain.&lt;/p&gt;

&lt;p&gt;As a young and (excessively) restless developer, Iâm constantly experimenting with new libraries and frameworks. The âProjectsâ directory on my laptop is a messy graveyard of half-finished Todo apps, CRUD blogs, and coding sandboxes created to try out a promising new language or technology. You probably know the type, or share some of these same symptoms.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://66.media.tumblr.com/8599b2611b8f19e9bb51bb629367a7ea/tumblr_o7pfsqcV6B1uk136vo1_250.gif&quot; alt=&quot;Dozens!&quot;&gt;&lt;/p&gt;

&lt;p&gt;I decided to check out &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember.js&lt;/a&gt; a year ago, and soon realized that I kept finding myself back here on &lt;a href=&quot;https://dockyard.com/blog&quot;&gt;ReefPoints&lt;/a&gt;. I was reading fantastic pieces by DockYard engineers on almost every topic pertaining to Ember development. I learned a tremendous amount about the various nooks and crannies of the framework, but more importantly, began to recognize what makes Ember such a great tool for building truly ~ambitious~ web applications.&lt;/p&gt;

&lt;p&gt;So when I read Michael Dupuisâ email to the Tufts CS group about DockYard looking for new developers, I knew that this would be a fantastic opportunity. Directly working alongside some of the most prolific OSS contributors and JavaScript engineers in the Boston area is not something to miss out on. DockYard takes their engineering seriously, and I really wanted to level up my engineering skills this summer. It was a perfect match.&lt;/p&gt;

&lt;p&gt;In the past couple of weeks, however, Iâve realized that thereâs far more to this place than just a deep knowledge of web development.&lt;/p&gt;

&lt;h2&gt;What makes DockYard so special?&lt;/h2&gt;

&lt;p&gt;One of the things that I immediately noticed clearly defines this place is the sheer amount of collective knowledge shared between everyone in the company. Iâve only just started to get to know people here, and it seems like each member of the twenty-two person team has a unique area of expertise. DockYarders include the creator of an incredible web framework, expert JavaScript and Ember.js engineers, Boston architectural enthusiasts, and craft beer sommeliers. If you put all of these people in a room together and have them work on creative projects, youâre bound to get great results. There is a contagious, inventive energy in the air that is noticeable right when you walk into the office, and you can tell that DockYarders are proud of the work that they do.&lt;/p&gt;

&lt;p&gt;Expertise and mastery of craft is ingrained in the culture here, but so is self-improvement and knowledge sharing. DockYard does a fantastic job of consulting and working with their clients, but they do just as great a job of training and educating their own employees.&lt;/p&gt;

&lt;p&gt;I&amp;#39;ve experienced this first hand. Despite how intimidating it could have been to pair program with an engineer on an Ember client project (and fumble around with an addon &lt;em&gt;that they created&lt;/em&gt;), it has never really felt that way. Itâs why every Thursday two DockYarders do an in-depth presentation on a topic of their choosing, which are then frequently taken to conferences around the country. Itâs why the Slack channels for technologies like Ember and Phoenix are constantly buzzing with questions and back-and-forth conversations about best practices. And itâs why youâre reading this blog post from me right now: sharing of experience is not just encouraged, itâs expected.&lt;/p&gt;

&lt;h2&gt;Time to get to work!&lt;/h2&gt;

&lt;p&gt;I think Iâm joining DockYard at a really exciting time for both the company and the software consultancy industry as a whole. Thereâs such a wide variety of interesting and challenging projects being started, and the tools with which to build them have never been more promising or enjoyable to use. DockYard recognizes this more than anything else, and makes sure to invest their time in projects and technologies that have the most future potential.&lt;/p&gt;

&lt;p&gt;My goal for the next three months is to learn as much as possible from the many talented individuals in the office, and hopefully be able to contribute in my own way. Iâm excited to get hands-on experience working with clients, but Iâm also looking forward to participating in the many traditions that separate DockYard from other companies: Wicked Good Ember, hallway talks, monthly outings, DockYard Fridays, and countless others. I know that at many points I will struggle, and perhaps even fail, but thatâs okay. In fact, thatâs what I signed up for - a challenging new experience. Hereâs to a great summer.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Today, User Experience is KingâWhy Your Technology Choices Should Reflect That</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/06/13/how-technology-choices-affect-user-experience" />
    <id>https://dockyard.com/blog/2016/06/13/how-technology-choices-affect-user-experience</id>
    
    <published>2016-06-13 00:00:00</published>
    <updated>2016-07-01 08:26:37</updated>
    <author><name>Maggie Gigler</name></author>
    <summary>Users expect both the responsiveness and functionality of native apps, but users also appreciate the convenience of the web. Learn how choosing single-page applications allows you to deliver both.</summary>
    <content type="html">&lt;p&gt;In Norton Justerâs &lt;em&gt;The Phantom Tollbooth&lt;/em&gt;, an intriguing character introduced as The Whether Man tells the protagonist Milo, âExpectations is the place you must always go to before you get to where you&amp;#39;re going. Of course, some people never go beyond Expectations, but my job is to hurry them along, whether they like it or not.â While Expectations is an actual locale in a childrenâs novel, web developers and designers should similarly go beyond Expectations, although the Whether Man is right in that some never do. In order to do so, one must recognize that in todayâs market, user experience reigns supreme. The most direct way to surpass Expectations is by delivering a user experience via a mobile web app but that feels like a native app (such as an iOS application that you purchase through the App Store).&lt;/p&gt;

&lt;p&gt;I had an English teacher in high school who said that you need to hold your readerâs hand through an essay, meaning your writing should be clear and easy to understand. Similarly, an application should deliver a user interface where a user can move intuitively and fluently through each piece of the application. That being said, that experience can only be as good as the tools that are used to create it. At DockYard, these tools include design strategy and Ember.js as our client-side framework to build the single page applications that we design and develop in-house. &lt;/p&gt;

&lt;p&gt;Single page applications, also known as client-side applications (as opposed to server-rendered applications), are web applications that upload to a single HTML page, dynamically updating the experience as the application is in use. Because of a client-side configuration, an application can respond to its users instantly. The design supports self-directed navigation, and the process is not disrupted by the reload of a page, which creates a more native feel. Further, these web applications cater to all variants of operating systems, and the framework we use to build these applicationsâEmber.jsâis backwards compatible, meaning there will be support for the long haul. Ember.js is also a versatile framework, so it can also be used to build can be used for hybrid apps, which live within a native app âshellâ but can be launched within a web browser (e.g. &lt;a href=&quot;http://www.linkedin.com&quot;&gt;LinkedIn&lt;/a&gt;, &lt;a href=&quot;https://www.groupon.com/&quot;&gt;Groupon&lt;/a&gt;, and &lt;a href=&quot;http://www.yahoo.com&quot;&gt;Yahoo&lt;/a&gt; use Ember.js).&lt;/p&gt;

&lt;p&gt;By design, these applications help to alleviate information overload and simplify navigation, which allows users to easily understand content. Users are therefore encouraged to engage further, whether they are aware of it or not. Before I started working here, I didnât really pay attention to UX. Now, Iâve noticed that users, including myself, become frustrated with longer-than-needed loading times and poor design. Importantly, applications that have faster response times yield higher conversions, so you get a greater return on investment with a single page app. Additionally, &lt;a href=&quot;https://blog.kissmetrics.com/loading-time/&quot;&gt;according to surveys done by Akamai and Gomez.com&lt;/a&gt;, nearly half of web users tend to abandon a site that isnât loaded within 3 seconds. 79% of web shoppers who have trouble with website performance say they wonât return to the site to buy again.&lt;/p&gt;

&lt;p&gt;When you think from the perspective of the user and strategize production with them in mind, you set yourself up for the greatest chance of success. You can ensure that your product is user-driven from the beginning by engaging design strategies, such as user research and prototyping, which can allow you to test initial hypotheses and create a product development roadmap. In this way, you can build reliably and save yourself time and frustration in the future.&lt;/p&gt;

&lt;p&gt;When applications are built well, its users have more agency to interact with the application more deeply. The single page web app model is at the forefront of mobile and web design and development, allowing both designers and developers to consider unique solutions. Please be advised: if youâre not paying attention, you can quickly find yourself in the Doldrums, and no one wants that.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Is design really just decoration?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/06/13/is-design-decoration" />
    <id>https://dockyard.com/blog/2016/06/13/is-design-decoration</id>
    
    <published>2016-06-13 00:00:00</published>
    <updated>2016-06-15 17:35:09</updated>
    <author><name>Mark Kaplan</name></author>
    <summary>What exactly is design? What does it mean to take a design-first approach to solving problems?</summary>
    <content type="html">&lt;p&gt;Historically, design has been &lt;a href=&quot;https://dockyard.com/blog/2016/04/19/is-it-time-to-call-a-designer&quot;&gt;an afterthought&lt;/a&gt;, the philosophy behind it being, âBuild something, then weâll employ design afterwards to improve its appeal.â That being said, as Mike Monteiro describes in &lt;a href=&quot;https://abookapart.com/products/youre-my-favorite-client&quot;&gt;Youâre My Favorite Client&lt;/a&gt;, bringing in designers once a product has been built is âakin to baking a cake, and &lt;em&gt;then&lt;/em&gt; hiring a baker to make it taste good.â&lt;/p&gt;

&lt;p&gt;In todayâs competitive marketplace, solid user experience design is a key advantageâyou canât succeed without it. Products can no longer succeed simply because they workâthere are too many other products competing for your usersâ attention. Users want to be impressed, and starting with exceptional UX design is a necessity to achieve that.&lt;/p&gt;

&lt;h2&gt;Visual design refinement &lt;em&gt;can&lt;/em&gt; be left for later.&lt;/h2&gt;

&lt;p&gt;Involving design brings up another common misconception that begs the question, âWhat is exactly is included in design?â If  we narrowly define design as color, typography, pattern, and layout, then it is understandable how that might be left for later. &lt;/p&gt;

&lt;p&gt;There are a few instances when it does make sense to begin a project with visual designâparticularly for branding and marketing campaigns. If youâre tasked with designing a digital experience for disinfectant wipes, you could use a design sprint to create and test visuals-and-copy concepts. You might come out with two concepts: one around âa motherâs instinct to care for her familyâ and the other âthe inconvenience of taking a sick day.â &lt;/p&gt;

&lt;p&gt;Without a strong visual component, it would tough to communicate these emotional concepts to potential consumers to gauge their response. One or more additional sprints could be used to flesh out the features and functionality of a campaign and application that leverage the concept that emerged from that initial sprint.&lt;/p&gt;

&lt;p&gt;However, in most of the projects we encounter, we&amp;#39;re not designing visual branding elements in isolation. Rather we&amp;#39;re working out complex experiences for products and services, along with the visual identity, the sum total of which &lt;em&gt;become&lt;/em&gt; the brand. In these, it does not make sense to lead with visual design. In order to design and create an effective, well-done user experience, one must establish who the users are, what the goals are for the product, and validate the productâs workflows. &lt;/p&gt;

&lt;h2&gt;Whatâs there beyond visual design?&lt;/h2&gt;

&lt;p&gt;A designer can barely &lt;a href=&quot;https://dockyard.com/blog/2015/09/10/design-is-about-systems&quot;&gt;cross the road&lt;/a&gt; without considering the systems and forces in place that are behind a variety of scenarios. While one potential solution for a poorly-designed crosswalk is creating a better-looking sign, most of the work behind that decision will be strategically thinking about the systems behind the crosswalk and relevant interactions.&lt;/p&gt;

&lt;p&gt;Many parts of our design-first approach to business problems at DockYard could go by different names. Here are some examples that are crucial to its process despite not being initially associated with design:&lt;/p&gt;

&lt;h3&gt;Product strategy&lt;/h3&gt;

&lt;p&gt;As designers, we ask lots of questions about why and how a product will serve its users, while at the same time achieving business goals of the product owner. &lt;/p&gt;

&lt;h3&gt;Research&lt;/h3&gt;

&lt;p&gt;Research at the early stages of a project can prevent expensive mistakes later down the line. Questions we ask could include:
- âDoes your audience actually want the product?â 
- âWhat does the audience think the product does?â 
- âDoes your audience exist? Is there a viable market for this product?â&lt;/p&gt;

&lt;h3&gt;Planning&lt;/h3&gt;

&lt;p&gt;Once we start building, we discuss what should be built first and how production can be implemented in manageable chunks, with testing and check-ups in between. We examine if there are certain parts of the product or service and any differences between them.&lt;/p&gt;

&lt;h3&gt;Testing&lt;/h3&gt;

&lt;p&gt;Having real users perform a specific task on a real product or a prototype is the only way to discover whether it actually works in the way which you expect. Moreover, user research allows you to potentially uncover and fix glitches early. User tests are more valid and the data is more authentic if an outside party helps run the tests in an impartial manner.&lt;/p&gt;

&lt;h3&gt;Setting up goals &amp;amp; measures&lt;/h3&gt;

&lt;p&gt;Finally, we operationally define success and how to measure that success. By setting a baseline early on, you have a standard to which to compare later performance.&lt;/p&gt;

&lt;p&gt;Planning, testing, and research are all parts of design. When applied early, these exercises are magnified in terms of effectiveness. Afterwards, during the product development stage, we&amp;#39;ll have some basis for making each of the hundreds decisions that go into your product.  &lt;/p&gt;
</content>
  </entry><entry>
    <title>Answering questions early with design sprints</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/06/13/answering-questions-early" />
    <id>https://dockyard.com/blog/2016/06/13/answering-questions-early</id>
    
    <published>2016-06-13 00:00:00</published>
    <updated>2016-06-15 17:35:09</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Learn how using Design Sprints to validate assumptions in the initial planning stages of your project helps ensure its success.</summary>
    <content type="html">&lt;p&gt;In this day and age, efficiency is crucialâwe live in a world where the rate at which we progress is almost unsettling. In business, efficiency becomes essential in that we must keep up with our competitors, not waste anyone&amp;#39;s time, and operate economically and efficiently, all without sacrificing quality. While strategy is possible without an outside party, weâre often too close to a situation to see the drawbacks and obstacles. &lt;/p&gt;

&lt;p&gt;Weâre often sensitive about the things we know best, and thatâs not a bad thingâit only makes sense that we should be so invested in our work. A new perspective is advantageous in that it allows for a number of unique observations, exposing potential pitfalls and eliminating assumptions. A design sprint can be a good way to enlist that outside perspective.&lt;/p&gt;

&lt;p&gt;A while back, I explained &lt;a href=&quot;https://dockyard.com/blog/2015/08/17/design-sprints-what-are-they-for&quot;&gt;what design sprints are for&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The purpose of a sprint is not to deliver a whole product, but a realistic model of a product experience. In a few cases a product experience may be small and focused enough to be encompassed entirely in the sprint. More likely, a design sprint focuses on a specific aspect of an application, and a single user story.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Action towards the implementation of a product may seem more favorable option than planning. However, strategizing and answering unknowns via a design sprint is an investment that will pay dividends by saving so much time and sparing a lot of frustration down the line. Further, involving all the different players (e.g. strategists, engineers, designers, potential users) allows us to brings realism to the project. &lt;/p&gt;

&lt;p&gt;The best time for a sprint is not after a project has already started, but before any implementation work has begun. A design sprint early in the planning stages will go a long way to reduce uncertainty and validate the current projectâs merit.  That way, your team can confidently focus on the projectâs success.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://hbr.org/2016/03/sprints-are-the-secret-to-getting-more-done&quot;&gt;Harvard Business Review&lt;/a&gt; recommends sprints because they help âfocus on whatâs important.â To get an idea of how a design sprint could work for you, check out the open source &lt;a href=&quot;https://dockyard.com/design-sprints&quot;&gt;Design Sprint Guide&lt;/a&gt; weâve produced to explain how design sprints can reduce uncertainty by efficiently testing business ideas. &lt;/p&gt;
</content>
  </entry><entry>
    <title>New to Elixir 1.3 - Kernel.pop_in</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/06/05/elixir-1-3-kernel-pop-in" />
    <id>https://dockyard.com/blog/2016/06/05/elixir-1-3-kernel-pop-in</id>
    
    <published>2016-06-05 00:00:00</published>
    <updated>2016-06-07 07:10:09</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Working with large objects just became easier</summary>
    <content type="html">&lt;p&gt;Back in February I wrote about &lt;a href=&quot;https://dockyard.com/blog/2016/02/01/elixir-best-practices-deeply-nested-maps&quot;&gt;how to work with deeply nested
maps&lt;/a&gt;. One missing piece was the ability to easily prune data
from a deeply nested map. Today I&amp;#39;d like to introduce you to
&lt;code&gt;Kernel.pop_in&lt;/code&gt; which will be available in Elixir 1.3.&lt;/p&gt;

&lt;p&gt;Given the following:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_map = %{
  foo: %{
    bar: %{
      baz: &amp;quot;my value&amp;quot;
    }
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In order to delete the &lt;code&gt;baz&lt;/code&gt; atom you would have to write something like
this:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;put_in(my_map, [:foo, :bar], %{})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For this contrite example it may not seem that bad. But let&amp;#39;s take a
look at another example:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_map = %{
  foo: %{
    bar: %{
      baz: &amp;quot;my value&amp;quot;,
      qux: &amp;quot;other value&amp;quot;
    }
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If we wanted to preserve the &lt;code&gt;qux&lt;/code&gt; atom we&amp;#39;d write:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;put_in(my_map, [:foo, :bar], Map.delete(my_map[:foo][:bar], :baz))
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we&amp;#39;re starting to see something that could get ugly. This is where
&lt;code&gt;Kernel.pop_in&lt;/code&gt; can help:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;pop_in(my_map, [:foo, :bar, :baz])
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That&amp;#39;s nice and clean! However, unlike the other accessor-based
functions this one returns a tuple:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{&amp;quot;my value&amp;quot;, %{foo: %{bar: %{qux: &amp;quot;other value&amp;quot;}}}} = pop_in(my_map, [:foo, :bar, :baz])
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first element in the tuple will be the value that is being removed.
The second element will be the new map.&lt;/p&gt;

&lt;p&gt;Elixir 1.3 comes packed with a bunch of improvements for the developer
experience like this one. Hopefully we can all start enjoying it soon!&lt;/p&gt;
</content>
  </entry><entry>
    <title>How to make sense of a complex project, fast</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/06/02/make-sense-complex-project-fast" />
    <id>https://dockyard.com/blog/2016/06/02/make-sense-complex-project-fast</id>
    
    <published>2016-06-02 00:00:00</published>
    <updated>2016-06-15 17:35:09</updated>
    <author><name>Mark Kaplan</name></author>
    <summary>The time and effort we spend together in up-front sense-making may not feel like âdesign.â But itâs one of the most important and best investments you can make.</summary>
    <content type="html">&lt;p&gt;We live in an increasingly complex world. Your business doesnât exist in a vacuum, and thereâs so much to keep track of. When you have a problem that needs solving, itâs often hard to define what that problem is, whoâs having it, and what the solution might look like. Everyone seems to have a different opinion. And just when you think youâre making progress trying to understand things, something changes. Or everything changes. No wonder folks become overloaded and frustrated&amp;thinsp;&amp;mdash;&amp;thinsp;what a mess! &lt;/p&gt;

&lt;h3&gt;Complex, dynamic systems often exist beyond understanding by any individual.&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/9X2i99sl.png&quot; alt=&quot;Aircraft Carrier&quot;&gt;
&lt;/br&gt;Image Credit: &lt;a href=&quot;http://www.telegraph.co.uk/finance/newsbysector/industry/defence/10723462/HMS-Queen-Elizabeth-Britains-new-aircraft-carrier-in-detail.html&quot;&gt;Telegraph&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No one person on an aircraft carrier understands all of the complex systems on board&amp;thinsp;&amp;mdash;&amp;thinsp;not even the captain. And yet, that ship is able to function as it does due to a network of common understandings and cooperation. Design Thinking is a set of tools and methods we can deploy to make sense of the jumble before solving problems. The goal isnât to simplify whatâs inherently complex, but rather to embrace that complexity through better, shared understanding. &lt;/p&gt;

&lt;p&gt;We take our first steps by wrapping our heads around what we already know or have. Working together, weâll create models, much like scientists do. This gives us something in common - something we can all point at and discuss. &lt;/p&gt;

&lt;p&gt;We often start with language, by naming things. From there, weâll create sketches collaboratively, defining concepts, showing relationships and allowing us to compare and contrast. Weâll do this iteratively, which increases our collective understanding over time. Knowing where we are today&amp;thinsp;&amp;mdash;&amp;thinsp;and then layering on where weâre trying to get to and how weâll know when we get there&amp;thinsp;&amp;mdash;&amp;thinsp;gives us a sound framework for future decision-making.&lt;/p&gt;

&lt;p&gt;One of our clientâs goals is to open up a system used internally to external customers, for self-service. The current system was developed over many years and has hundreds of screens and functions. Itâs not only a complex workflow - itâs a complicated user interface, a ratâs nest of tabs and sub-tabs and pop-ups that open pop-ups.&lt;/p&gt;

&lt;p&gt;We couldnât possibly begin to redesign it without trying to make sense of it first. But how? This is a problem best approached from several directions.&lt;/p&gt;

&lt;p&gt;First, weâd gain some level of shared understanding of the present system. Like that aircraft carrier, it seems like not one person understands the whole system. Weâd talk to the product owners, engineers, support team, and existing users. Weâd also make our own way around the app. Along the way, weâd create and validate mental models and sketches. &lt;/p&gt;

&lt;h3&gt;The goal is orientation, not complete understanding.&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/ioyW0XI.jpg&quot; alt=&quot;Neighborhood Map and Street Map comparison&quot;&gt;
&lt;/br&gt;Image Credits: &lt;a href=&quot;http://www.boston-discovery-guide.com/boston-neighborhoods.html&quot;&gt;Boston Discovery Guide&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Template:Location_map_Boston&quot;&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Second, weâd look toward the future. Weâd talk to the business stakeholders, to gain their understanding of the problem weâre trying to solve, and for whom it is a problem. Do they all agree? Weâd also examine the external contexts that the system will exist in: user, industry, and technology.&lt;/p&gt;

&lt;p&gt;Third, weâd talk to the prospective self-service users. Our client isnât the only player in its huge market, and most of their customers are already familiar with several competing systems. By comparing and contrasting the language and mental models of these customers with what we know about the existing internally-focused system, weâd discover where we have alignment and where we have conflict.&lt;/p&gt;

&lt;p&gt;Because itâs always easier to leverage entrenched behaviors than to try to instigate new behaviors, our insights will directly influence the prioritization, naming, and design of the features, functions, and flows of the new system. Weâll even spot opportunities to be better than the competition!&lt;/p&gt;

&lt;p&gt;Finally, weâd design and construct prototypes&amp;thinsp;&amp;mdash;&amp;thinsp;and test them.&lt;/p&gt;

&lt;p&gt;The time and effort we spend together in up-front sense-making may not feel like âdesign.â But itâs one of the most important and best investments you can make.&lt;/p&gt;
</content>
  </entry><entry>
    <title>TIL: Ecto supports a query inside another query</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/27/til-ecto-supports-query-inside-query" />
    <id>https://dockyard.com/blog/2016/05/27/til-ecto-supports-query-inside-query</id>
    
    <published>2016-05-27 00:00:00</published>
    <updated>2016-06-07 07:10:09</updated>
    <author><name>Marin Abernethy</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;If you read the &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Query.html&quot;&gt;Ecto.Query&lt;/a&gt; documentation, one of the first sections explains how
Ecto queries are composable. Meaning, we can extend a query after creating it. Like so:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;query = from e in Event,
  where: e.category == ^event.category

case event.host do
  host -&amp;gt; from e in query, where: e.host == ^host
  _ -&amp;gt; query
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This was a feature that I learned a while after starting Elixir (apparently I didn&amp;#39;t read the docs well enough).
And it is totally awesome. But &lt;strong&gt;today I learned&lt;/strong&gt; Ecto also supports nested queries!&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;last_event = from e in Event,
  distinct: e.id,
  order_by: [desc: e.inserted_at]

query = from a in Attendee, preload: [events: ^last_event]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here, we are referencing a query (&lt;code&gt;last_event&lt;/code&gt;) from within another query. How exciting! It is also important to mention
that Ecto 2.0 supports &lt;a href=&quot;https://github.com/elixir-lang/ecto/pull/1231&quot;&gt;subqueries&lt;/a&gt; in the &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;join&lt;/code&gt; fields (see example below). This makes queries even more malleable and powerful.
Hope you enjoy it as much as I do!&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;query = from e in Event, select: e
q = from e in subquery(query), select: e.summary
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;</content>
  </entry><entry>
    <title>Narwin-Pack: A PostCSS Package for DRY and Efficient CSS</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/27/narwin-pack-the-postcss-package" />
    <id>https://dockyard.com/blog/2016/05/27/narwin-pack-the-postcss-package</id>
    
    <published>2016-05-27 00:00:00</published>
    <updated>2016-07-01 08:26:37</updated>
    <author><name>Cory Tanner</name></author>
    <summary>After DockYardâs recent transition to PostCSS, we realized that we needed better plugin organization. So we created narwin-pack. Hereâs an overview of the plugins that make up narwin-pack and why our UXD team chose each PostCSS plugin.</summary>
    <content type="html">&lt;p&gt;In my last blog post, &lt;a href=&quot;https://dockyard.com/blog/2016/02/11/transition-to-postcss&quot;&gt;Why DockYard transitioned to PostCSS&lt;/a&gt;, I explained why our UXD team adopted &lt;a href=&quot;https://github.com/postcss/postcss&quot;&gt;PostCSS&lt;/a&gt; into our development process.&lt;/p&gt;

&lt;p&gt;During the transition process we realized it would be best to only use PostCSS plugins that meet two criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encourages DRY CSS&lt;/li&gt;
&lt;li&gt;Simplifies our development process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thatâs when &lt;a href=&quot;https://github.com/DockYard/narwin-pack&quot;&gt;narwin-pack&lt;/a&gt; was born, An easy-to-use PostCSS package that holds all six of our plugins in one easy-to-use package.&lt;/p&gt;

&lt;p&gt;Having many plugins bundled into one package that can easily be included in our projects is valuable to our team. It gives our UXD team a structured environment to develop CSS.&lt;/p&gt;

&lt;p&gt;If another UX developer wants to add a plugin to narwin-pack a discussion is had within the narwin-pack repository and we discuss the pros and cons of using that plugin. If everyone agrees that a plugin is needed then it will be added to narwin-pack.&lt;/p&gt;

&lt;p&gt;PostCSS has options for hundreds of plugins that you can include in your project. Having only one package to use for our projects provides consistency, knowing that every developer within out team will be using the same plugins.&lt;/p&gt;

&lt;p&gt;The plugins in narwin-pack are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jonathantneal/postcss-partial-import&quot;&gt;postcss-partial-import&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/postcss/postcss-custom-properties&quot;&gt;postcss-custom-properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/postcss/postcss-nested&quot;&gt;postcss-nested&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/postcss/postcss-calc&quot;&gt;postcss-calc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/postcss/autoprefixer&quot;&gt;autoprefixer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jonathantneal/postcss-svg-fragments&quot;&gt;postcss-svg-fragments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;1. postcss-partial-import&lt;/h1&gt;

&lt;p&gt;The postcss-partial-import plugin provides the environment for a modular CSS file structure. You can have multiple CSS files and then with the help of postcss-partial-import we merge all our CSS files into one central file that the browser will use.&lt;/p&gt;

&lt;p&gt;The ability to have multiple CSS files but only reference one CSS file in our HTML is important for page performance. The browser now only has to ask the server for one CSS file. At the same time using multiple CSS files lets us modularly organize our CSS based on BEM &lt;a href=&quot;https://github.com/DockYard/styleguides/blob/master/ux-dev/class-naming-conventions.md&quot;&gt;naming conventions&lt;/a&gt; and SMACSS file architectures.&lt;/p&gt;

&lt;p&gt;Modular CSS file structure:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;styles/
  modules/
    header.css
    footer.css
    nav.css
  base.css
  load.css
  layout.css
  type.css
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Using this CSS architecture we can now add all of those CSS files into one central CSS file. Our CSS file with &lt;code&gt;@imports&lt;/code&gt; pointing to other CSS files could look like the following:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;directive&quot;&gt;@import&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;load.css&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;directive&quot;&gt;@import&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type.css&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;directive&quot;&gt;@import&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;modules/header.css&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;directive&quot;&gt;@import&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;modules/footer.css&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The plugin will recognize the &lt;code&gt;@import&lt;/code&gt; and add the contents of the referenced CSS files into this one CSS file.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/x6596A7.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;h1&gt;2. postcss-custom-properties&lt;/h1&gt;

&lt;p&gt;Who doesnât love using variables!&lt;/p&gt;

&lt;p&gt;The use of variables in CSS has been a hot topic lately, and eventually all browsers will support them. Firefox and Chrome already have &lt;a href=&quot;http://caniuse.com/#search=variables&quot;&gt;support &lt;/a&gt;, but we are still waiting on Edge and mobile browser support. Until all browsers support variables, we will need a plugin.&lt;/p&gt;

&lt;p&gt;I think most developers would agree with me when I say that I would rather remember a color for its name, as opposed to its hex code. Further, we make sure to organize our variables with naming conventions so they are easy to both read and use.&lt;/p&gt;

&lt;p&gt;An example of how we organize our variables in our &lt;code&gt;load.css&lt;/code&gt; file is as follows:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pseudo-class&quot;&gt;:root&lt;/span&gt; {
  &lt;span class=&quot;comment&quot;&gt;/* COLORS */&lt;/span&gt;
  &lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;key&quot;&gt;-white&lt;/span&gt;: &lt;span class=&quot;color&quot;&gt;#FFFFFF&lt;/span&gt;;
  &lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;key&quot;&gt;-green&lt;/span&gt;: &lt;span class=&quot;color&quot;&gt;rgb(61, 154, 104)&lt;/span&gt;;
    &lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;float&quot;&gt;-75&lt;/span&gt;&lt;span class=&quot;key&quot;&gt;-green&lt;/span&gt;: &lt;span class=&quot;color&quot;&gt;rgba(61, 154, 104, .75)&lt;/span&gt;;

  &lt;span class=&quot;comment&quot;&gt;/* FONT WEIGHTS */&lt;/span&gt;
  &lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;key&quot;&gt;-light&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;200&lt;/span&gt;;
  &lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;key&quot;&gt;-bold&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;600&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice that we break our variables down into sections and give them easy to use names with indentation. This way other developers can look at this CSS file and know what everything does.&lt;/p&gt;

&lt;p&gt;An important thing to remember is that if you want variables available globally, wrap them in a &lt;code&gt;:root {}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hereâs a quick example of how to use variables:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pseudo-class&quot;&gt;:root&lt;/span&gt; {
  &lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;key&quot;&gt;-green&lt;/span&gt;: &lt;span class=&quot;color&quot;&gt;rgb(61, 154, 104)&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In other CSS files, you can just use the variable name in place of the color code.&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.text&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;(&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;value&quot;&gt;-green&lt;/span&gt;);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The output of this will be the &lt;code&gt;rgb&lt;/code&gt; color code. This is simple but allows us to organize colors and other variables.&lt;/p&gt;

&lt;h1&gt;3. postcss-nested&lt;/h1&gt;

&lt;p&gt;Nesting is a technique that we use, but in moderation. We make sure not to nest class names for easier âBEM-ingâ because it can be difficult to try to find BEM classes that are made with nesting. We canât search for &lt;code&gt;.hero__heading&lt;/code&gt; if &lt;code&gt;__heading&lt;/code&gt; was added to &lt;code&gt;.hero&lt;/code&gt; with nesting.&lt;/p&gt;

&lt;p&gt;Incorrect Example:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.hero&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;margin-top&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;10px&lt;/span&gt;;
  &lt;span class=&quot;error&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;key&quot;&gt;__heading&lt;/span&gt; {
    &lt;span class=&quot;key&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;blue&lt;/span&gt;;
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Using BEMâs naming conventions without nesting keeps our CSS files readable and searchable.&lt;/p&gt;

&lt;p&gt;Correct Example:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.hero&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;margin-top&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;10px&lt;/span&gt;;
}
&lt;span class=&quot;class&quot;&gt;.hero__heading&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;blue&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We do use nesting for media queries, pseudo elements/classes and parent dependent classes styles.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.nav__links&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;float&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;right&lt;/span&gt;;
  .&lt;span class=&quot;key&quot;&gt;body--black&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&amp;amp;&lt;/span&gt; {
    &lt;span class=&quot;key&quot;&gt;border-color&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;(&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;value&quot;&gt;-white&lt;/span&gt;);
  }
  .&lt;span class=&quot;key&quot;&gt;body--white&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&amp;amp;&lt;/span&gt; {
    &lt;span class=&quot;key&quot;&gt;border-color&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;(&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;value&quot;&gt;-black&lt;/span&gt;);
  }
}

&lt;span class=&quot;class&quot;&gt;.nav__link&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;(&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;value&quot;&gt;-green&lt;/span&gt;);
  &lt;span class=&quot;error&quot;&gt;&amp;amp;&lt;/span&gt;.&lt;span class=&quot;key&quot;&gt;is-active&lt;/span&gt;,
  &lt;span class=&quot;error&quot;&gt;&amp;amp;&lt;/span&gt;:&lt;span class=&quot;value&quot;&gt;focus&lt;/span&gt;,
  &lt;span class=&quot;error&quot;&gt;&amp;amp;&lt;/span&gt;:&lt;span class=&quot;value&quot;&gt;hover&lt;/span&gt; {
    &lt;span class=&quot;key&quot;&gt;color&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;(&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;float&quot;&gt;-50&lt;/span&gt;&lt;span class=&quot;value&quot;&gt;-green&lt;/span&gt;);
  }
  &lt;span class=&quot;directive&quot;&gt;@media&lt;/span&gt; (&lt;span class=&quot;key&quot;&gt;max-width&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;599px&lt;/span&gt;) {
    &lt;span class=&quot;key&quot;&gt;display&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;block&lt;/span&gt;;
  }
  &lt;span class=&quot;directive&quot;&gt;@media&lt;/span&gt; (&lt;span class=&quot;key&quot;&gt;min-width&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;600px&lt;/span&gt;) {
    &lt;span class=&quot;key&quot;&gt;display&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;inline-block&lt;/span&gt;
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The block of CSS above is a simple example of good nesting according to the guidelines we have set for ourselves.&lt;/p&gt;

&lt;h1&gt;4. postcss-calc&lt;/h1&gt;

&lt;p&gt;Having this plugin included in narwin-pack is a result of having postcss-custom-properties. With this plugin we can include variables inside &lt;code&gt;calc()&lt;/code&gt; equations if we would like.&lt;/p&gt;

&lt;p&gt;Input:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;pseudo-class&quot;&gt;:root&lt;/span&gt; {
  &lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;key&quot;&gt;-font-size&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;18px&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Any CSS file within the same root folder:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.text&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;font-size&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;(&lt;span class=&quot;error&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;(&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;value&quot;&gt;-font-size&lt;/span&gt;) &lt;span class=&quot;error&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;float&quot;&gt;2&lt;/span&gt;);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.text&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;font-size&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;36px&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h1&gt;5. postcss-svg-fragments&lt;/h1&gt;

&lt;p&gt;A downside of using the &lt;a href=&quot;https://css-tricks.com/svg-symbol-good-choice-icons/&quot;&gt;symbol&lt;/a&gt; method for multiple SVGâs is that itâs not supported with inline CSS, only inline HTML. SVG Fragments solves this problem for us.&lt;/p&gt;

&lt;p&gt;Without this plugin, we would need to have individual SVG files for &lt;code&gt;background-images&lt;/code&gt; in CSS, and the browser would have to pull multiple SVG files when loading a page. The plugin postcss-svg-fragments solves this by doing what its name implies, it adds SVG fragments into CSS.&lt;/p&gt;

&lt;p&gt;We take all our SVG files and add them to &lt;a href=&quot;https://icomoon.io/app/#/&quot;&gt;icomoon.io&lt;/a&gt;, generate a new SVG with a &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; that has an unique &lt;code&gt;id&lt;/code&gt;. Then we add the new SVG code to our &lt;code&gt;defs.svg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Input:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.background-patter&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;background-image&lt;/span&gt;: &lt;span class=&quot;function&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;url(&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;defs.svg#pattern&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;)&lt;/span&gt;&lt;/span&gt;;
  &lt;span class=&quot;key&quot;&gt;fill&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;blue&lt;/span&gt;;
  &lt;span class=&quot;key&quot;&gt;stroke&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;black&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.background-patter&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;background-image&lt;/span&gt;: &lt;span class=&quot;function&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;url(&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/* SVG data */&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;)&lt;/span&gt;&lt;/span&gt;;
  &lt;span class=&quot;key&quot;&gt;fill&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;blue&lt;/span&gt;;
  &lt;span class=&quot;key&quot;&gt;stroke&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;black&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h1&gt;6. autoprefixer&lt;/h1&gt;

&lt;p&gt;One of the most used tools by HTML/CSS developers is autoprefixer. Before having autoprefixer as a PostCSS plugin, we would go to &lt;a href=&quot;http://caniuse.com/&quot;&gt;caniuse.com&lt;/a&gt; to see what CSS rules still needed browser prefixes. Even developers who donât use PostCSS use the autoprefixer plugin in their projects.&lt;/p&gt;

&lt;p&gt;Now, we have a plugin that looks at the CSS and searches for what prefixes are needed. Then adds them into the compiled CSS file according to how itâs configured. Autoprefixer lets us configure custom browser support.&lt;/p&gt;

&lt;p&gt;Example with autoprefixer:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.block&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;display&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;flex&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.block&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;display&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;-webkit-box&lt;/span&gt;;
  &lt;span class=&quot;key&quot;&gt;display&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;-webkit-flex&lt;/span&gt;;
  &lt;span class=&quot;key&quot;&gt;display&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;-ms-flexbox&lt;/span&gt;;
  &lt;span class=&quot;key&quot;&gt;display&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;flex&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h1&gt;Takeaways&lt;/h1&gt;

&lt;p&gt;We choose these plugins because they are intended to make our lives easier as developers. Further, these plugins will help us develop DRY and efficient CSS, which is significant because that is the interface with which the user will interact.&lt;/p&gt;

&lt;p&gt;If chosen carefully, the combination of plugins and self-set guidelines can foster a great environment in which to make exceptional CSS.&lt;/p&gt;
</content>
  </entry><entry>
    <title>TIL: Elixir pattern matching for argument equality</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/26/til-elxir-pattern-matching-for-argument-equality" />
    <id>https://dockyard.com/blog/2016/05/26/til-elxir-pattern-matching-for-argument-equality</id>
    
    <published>2016-05-26 00:00:00</published>
    <updated>2016-06-07 07:10:09</updated>
    <author><name>Marin Abernethy</name></author>
    <summary>pattern matching versus guard expressions</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://elixir-lang.org/getting-started/pattern-matching.html&quot;&gt;Pattern matching&lt;/a&gt; and &lt;a href=&quot;http://elixir-lang.org/getting-started/case-cond-and-if.html#expressions-in-guard-clauses&quot;&gt;guard expressions&lt;/a&gt; are fundamental to
writing recursive function definitions in &lt;a href=&quot;http://elixir-lang.org/&quot;&gt;Elixir&lt;/a&gt;. Sometimes guard clauses and pattern matching
can be used for the same purpose. For example:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# pattern matching
defmodule Exponent do
  def power(value, 0), do: 1
  def power(value, n), do: value * power(value, n - 1)
end

# guard expression
defmodule Exponent do
  def power(value, n) when n == 0, do: 1
  def power(value, n), do: value * power(value, n - 1)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In both cases above, we only want the first &lt;code&gt;power&lt;/code&gt; function to run when the second argument is equal to &lt;code&gt;0&lt;/code&gt;.
When it is as simple as equality, I tend to use the pattern matching syntax. I typically leave the guard for more complex
logic like &lt;code&gt;when rem(x, divisor) == 0&lt;/code&gt;. However, to check whether one argument is equal to another I thought a guard was neccessary: &lt;code&gt;when a == b&lt;/code&gt;.
But, &lt;strong&gt;today I learned&lt;/strong&gt;, this can also be handled with pattern matching, like so:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# guard
def equality(a, b) when a == b, do: IO.puts &amp;quot;equal&amp;quot;
def equality(a, b), do: IO.puts &amp;quot;not equal&amp;quot;

# pattern matching
def equality(a, a), do: IO.puts &amp;quot;equal&amp;quot;
def equality(a, b), do: IO.puts &amp;quot;not equal&amp;quot;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Tada! There you have it. It seems so simple I don&amp;#39;t know how I hadn&amp;#39;t tried it earlier!&lt;/p&gt;
</content>
  </entry><entry>
    <title>How does project communication become complex?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/25/how-does-project-communication-become-complex" />
    <id>https://dockyard.com/blog/2016/05/25/how-does-project-communication-become-complex</id>
    
    <published>2016-05-25 00:00:00</published>
    <updated>2016-06-07 07:10:09</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Learning about communication patterns in larger teams</summary>
    <content type="html">&lt;p&gt;Projects of larger scale or longer duration often involve a large design team. We typically keep everyone informed and share information efficiently on teams roughly the size of a large family. But we don&amp;#39;t have that intuitive understanding of how teams work once they get much larger than that. &lt;/p&gt;

&lt;p&gt;As Iâve gotten the chance to look into how larger teams work on projects, I realized that they have the potential to get too complex for one person to understand, and therefore communication requires careful attention and structure.&lt;/p&gt;

&lt;p&gt;On a project of any size, there is inherent value in communication: it allows everyone to know what theyâre working on, and to avoid getting in the way of others. The value of clear and efficient communication is a subject for another time. What Iâm most concerned with here is how the level of complexity grows with team size.&lt;/p&gt;

&lt;p&gt;Letâs see what happens as the number of people on a team grows. Weâll assume the hierarchical structure stays the same, leaving everyone roughly on the same level and allowing all team members to communicate with one another like they would on a small team.&lt;/p&gt;

&lt;h2&gt;A team of two or more needs to communicate.&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/cj1M4K3.jpg&quot; alt=&quot;A small team communicates simply&quot;&gt;&lt;/p&gt;

&lt;p&gt;With a team size of two, everyoneâs ideas and questions can be exchanged freely, and all team members are on the same page as these conversations happen.&lt;/p&gt;

&lt;h2&gt;With more people on a team, communication adds up.&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/JaKGFon.jpg&quot; alt=&quot;larger team needs more communication&quot;&gt;&lt;/p&gt;

&lt;p&gt;If team communication style stays the same as a team grows, eventually it becomes more and more difficult for everyone to tell everyone else everything. At first it may look like the complexity of communication grows in a linear way, along with team size. But the pattern soon changes. &lt;/p&gt;

&lt;h2&gt;On larger teams, unmanaged communication becomes overwhelming.&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/hSl0xUo.jpg&quot; alt=&quot;A very large team needs even more!&quot;&gt;&lt;/p&gt;

&lt;p&gt;If everyone keeps telling everyone everything, without a defined structure to contain those conversations, the amount of communications will grow (nearly) exponentially faster, even as team size grows in a linear fashion.&lt;/p&gt;

&lt;p&gt;Remember that math problem from school, where youâd count the number of combinations of several objects? The teacher would make you go through manually counting the combinations for 2, 3, and maybe 4 objects until at 5 or 6 youâd determine that the number of combinations gets really big really fast. This is the same pattern I suspect would emerge if we allowed a flat structure of everyone talking to everyone, with no teams or management effort, for a large group of people. &lt;/p&gt;

&lt;h2&gt;Manage the conversations on larger teams. Because you have to.&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/emvoO7J.jpg&quot; alt=&quot;layered communication&quot;&gt;&lt;/p&gt;

&lt;p&gt;The answer to the math problem is structure. As team sizes grow, managers or team leaders emerge who become responsible for keeping on top of communications within a smaller team (think - the drawing of four people above) as well as for relaying that information to other team leaders. &lt;/p&gt;

&lt;h2&gt;Reinventing the wheel?&lt;/h2&gt;

&lt;p&gt;The need for management is not a new concept. As I was discovering it for myself, I was surely reinventing the wheel. Colleagues advised that the number of connections between nodes is described by &lt;a href=&quot;https://en.wikipedia.org/wiki/Metcalfe%27s_law&quot;&gt;Metclafeâs Law&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Iv59ich.png&quot; alt=&quot;Metclafeâs Law&quot;&gt;&lt;/p&gt;

&lt;p&gt;The information exchange in a group could be managed by breaking down &amp;amp; &lt;a href=&quot;https://en.wikipedia.org/wiki/Stakeholder_management&quot;&gt;managing different stakeholders&lt;/a&gt; depending on their influence (power) and influence level. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/MpNKIY0.png&quot; alt=&quot;Stakeholder Management&quot;&gt; &lt;/p&gt;

&lt;p&gt;I also learned that &lt;a href=&quot;https://blog.bufferapp.com/small-teams-why-startups-often-win-against-google-and-facebook-the-science-behind-why-smaller-teams-get-more-done&quot;&gt;coordination cost&lt;/a&gt; becomes one of the factors in determining the productivity of a team.&lt;/p&gt;

&lt;p&gt;All these are great ways to look at getting things done with more perspective than I would have had before I took on a management role. Re-discovering some of these principles for myself, and learning from colleagues has been a rewarding process - and I canât wait to see whatâs next!&lt;/p&gt;
</content>
  </entry><entry>
    <title>{{component helper}}</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/13/component-helper" />
    <id>https://dockyard.com/blog/2016/05/13/component-helper</id>
    
    <published>2016-05-13 00:00:00</published>
    <updated>2016-06-07 07:10:09</updated>
    <author><name>Romina Vargas</name></author>
    <summary>Help optimize your code with the component helper, in conjunction with other helpers</summary>
    <content type="html">&lt;p&gt;At DockYard, one pattern that we&amp;#39;ve been noticing in some of our projects is
needing to render different components based on some value. This value could
come from a computed property, a model attribute, etc. Typically, this means
that your template will contain some branching logic to figure out the
appropriate template to render. A helpful helper that became available pre-Ember
2.0 is the &lt;code&gt;{{component}}&lt;/code&gt;. With its help, we can clean up our template logic.&lt;/p&gt;

&lt;p&gt;A distinguishing factor between the &lt;code&gt;{{component}}&lt;/code&gt; helper and the traditional
component invocation is that the helper expects the component name as the first
parameter following the helper name, and will dynamically render out the component
specified by that parameter. An arbitrary number of parameters may follow the
component name; these are what the rendered component expects.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{{component myComponentName param2=param2 param3=param3 ...}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Suppose we have a &lt;code&gt;Food&lt;/code&gt; model. And each &lt;code&gt;Food&lt;/code&gt; model instance has a &lt;code&gt;taste&lt;/code&gt;
attribute. We want to render a certain template depending on the string value of
&lt;code&gt;food.taste&lt;/code&gt;. Prior to having the &lt;code&gt;{{component}}&lt;/code&gt; helper, we&amp;#39;d do something like
the following:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// food/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
const { Component, &lt;span class=&quot;key&quot;&gt;computed&lt;/span&gt;: { equal } } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;key&quot;&gt;isSpicy&lt;/span&gt;: equal(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;food.taste&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;spicy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;isSweet&lt;/span&gt;: equal(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;food.taste&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;sweet&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! food/template.hbs }}

{{#if isSpicy}}
  {{food/spicy-food food=food}}
{{else if isSweet}}
  {{food/sweet-food food=food}}
{{else}}
  {{food/other-food food=food}}
{{/if}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We defined a couple of computed properties and threw in some &lt;code&gt;if&lt;/code&gt; statements
in our template to dictate which component to render based on the food taste.
But we can do better! Let&amp;#39;s see how our app cleans up when using the helper.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// food/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
const { Component, computed, get } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;key&quot;&gt;tastyComponentName&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;food.taste&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      let foodTaste = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;food.taste&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;food/&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{foodTaste}-food&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
    }
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! food/template.hbs }}

{{component tastyComponentName food=food}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Nice. Our template became a one-liner, and we were able to remove the
computed properties that we had to define for each food taste that we
wanted to render a separate component for. All of the logic  is now consolidated
into one computed that returns the name of the component that should be rendered.
We can pass this property as the second argument inside &lt;code&gt;{{component}}&lt;/code&gt;.  If we
wanted to later introduce new food tastes and components to go along with them,
no changes would need to be made in these two files, since &lt;code&gt;tastyComponentName&lt;/code&gt;
takes care of all cases.&lt;/p&gt;

&lt;h2&gt;More powerful templates&lt;/h2&gt;

&lt;p&gt;In the above example, we are using the computed property &lt;code&gt;tastyComponentName&lt;/code&gt; to
name our template. But it&amp;#39;s not immediately obvious what the template actually is
without looking at the computed property itself. We can forgo the CP altogether
and use Handlebars subexpressions to keep all logic within the template.&lt;/p&gt;

&lt;p&gt;Recently, &lt;a href=&quot;https://twitter.com/sugarpirate_&quot;&gt;Lauren&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/Martndemus&quot;&gt;Marten&lt;/a&gt; released the
&lt;a href=&quot;https://github.com/DockYard/ember-composable-helpers&quot;&gt;ember-composable-helpers&lt;/a&gt; addon whose aim is to make
logic in your Ember templates more declarative. How convenient that this addon
complements &lt;code&gt;{{component}}&lt;/code&gt; well! The helpers within &lt;code&gt;ember-composable-helpers&lt;/code&gt;
can be used in different combinations to format your component name depending
on your needs. Furthermore, Ember itself ships with some
&lt;a href=&quot;http://emberjs.com/api/classes/Ember.Templates.helpers.html&quot;&gt;built-in helpers&lt;/a&gt; that can be used inside our templates as well.&lt;/p&gt;

&lt;p&gt;The Ember helper &lt;code&gt;concat&lt;/code&gt; is one of the helpers we use fairly often. It&amp;#39;s
common to name components based on a value of an attribute. In our example,
the component name is based on &lt;code&gt;food.taste&lt;/code&gt;. How would we modify our example
to make use of the &lt;code&gt;concat&lt;/code&gt; helper?&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! food/template.hbs }}

{{component (concat &amp;quot;food/&amp;quot; food.taste &amp;quot;-food&amp;quot;) food=food}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And just like that, the &lt;code&gt;food/component.js&lt;/code&gt; file is no longer needed. The &lt;code&gt;concat&lt;/code&gt;
helper replaces the computed property entirely. If the value of &lt;code&gt;food.taste&lt;/code&gt; is
&lt;code&gt;sweet&lt;/code&gt;, then the helper will output &lt;code&gt;food/sweet-food&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another useful helper that works well in conjunction with &lt;code&gt;concat&lt;/code&gt; is &lt;code&gt;dasherize&lt;/code&gt;.
This helper is part of &lt;code&gt;ember-composable-helpers&lt;/code&gt; addon and will take care of
lowercasing and dasherizing a given value. Sometimes, we have to work with camelized
values, and using &lt;code&gt;dasherize&lt;/code&gt; will convert them to a more desired format. Here&amp;#39;s
an example of how the helpers would be used together:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{{component (concat &amp;quot;food/&amp;quot; (dasherize food.taste) &amp;quot;-food&amp;quot;) food=food}}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this case, if the value of &lt;code&gt;food.taste&lt;/code&gt; is &lt;code&gt;SuperSour&lt;/code&gt;, then our rendered
component will be &lt;code&gt;food/super-sour-food&lt;/code&gt;. With all the helpers we have available
to us, think of all the combination possibilities!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Transitioning into Tech: From Googling âWhat is Ember.js?â to Interning at a Software Consultancy</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/11/transitioning-into-tech-from-googling-what-is-ember-to-interning" />
    <id>https://dockyard.com/blog/2016/05/11/transitioning-into-tech-from-googling-what-is-ember-to-interning</id>
    
    <published>2016-05-11 00:00:00</published>
    <updated>2016-06-07 07:10:09</updated>
    <author><name>Maggie Gigler</name></author>
    <summary>I was conducting psychiatric research at one of the nationâs oldest hospitals. Now I intern at DockYard, a software consultancy thatâs at the forefront of web design and development. Here are my observations from my first thirty days.</summary>
    <content type="html">&lt;p&gt;âEmma, have you ever heard of Ember?â I asked my roommate, a friend of mine from college who works as a user experience (UX) designer at a tech company here in Boston. I was looking for marketing positions and came across a software consultancy company called DockYard. I was drawn to their professional yet approachable feel: While they had built software applications for several big name clients (e.g. NASDAQ, the Democratic National Committee, Constant Contact), the language they used was straightforward and sincere. Whatâs more, they were a startup that didnât feel the need to have the word âawesomeâ splashed all over their website, and their job titles didnât include the words âninjaâ or âjedi.â It was an exciting find.&lt;/p&gt;

&lt;p&gt;At the time, I wasnât familiar with Ember.js, Phoenix, or Elixir, which are several of the technologies we use here at DockYard in web application design and development. My background is in psychology and research, and I previously worked in the Department of Psychiatry at Massachusetts General Hospital (MGH). But I figured Iâm a millennial, right? I grew up as the sophistication and use of the Internet took off on a global scale, and I can write HTML/CSS. If on one end of the spectrum you have my father, who is a businessman yet has neither an e-mail address nor a computer in his office, and on the other end you have your Mark Zuckerbergs and your Tim Berners-Lees of the world, then I fall somewhere in the middle. As I sat there wavering between the feelings of apprehension and audacity, I remembered my dad saying that the guy who leads the league in home runs usually also leads the league in strikeouts. So, I decided that I had nothing to lose and went for it: I filled out the âJoin Usâ form on DockYardâs website, and now Iâm sitting here reflecting on my first thirty days as a marketing intern.&lt;/p&gt;

&lt;p&gt;Being new can be awkward as you try to orient yourself within the organization, but you also have the unique opportunity to look at something from an original, unlearned perspective.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://imgur.com/8kKOeAA&quot;&gt;&lt;img src=&quot;http://i.imgur.com/8kKOeAA.gif&quot; title=&quot;source: imgur.com&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The reaction you fear as a new employee when youâre about to say nearly anything&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What I realized is that while Iâve always had a lot of respect for web developers and designers, I had never considered the future of tech in terms of the long-term viability of software applications or what that means for these roles. Admiration is not the same thing as appreciation, because to truly appreciate what someone does, you have to recognize the skill that it requires and the challenges facing that industry. Itâs easy to take software and other forms of technology for granted without considering the engineering and design that have gone into creating them.&lt;/p&gt;

&lt;p&gt;Prior to my interview at DockYard, I found it nearly impossible to find material that would explain Ember.js, Phoenix, or Elixir at a level that someone who was tech-savvy but not a developer could grasp (e.g., me). As I have an acute dislike of that left-out, lost feeling that accompanies not fully understanding a topic, Iâve been absorbing as many new concepts as I can while also learning about DockYardâs approach to design and engineering. Whatâs really impressed me in my first month is the careful consideration about the long-term viability of the applications we create.&lt;/p&gt;

&lt;p&gt;One can further see the foresight of DockYardâs leadership in the deliberate technology choices that we make. For example, at DockYard we specialize in single-page applications that have an average shelf-life of ten years. The average iOS application that you purchase in the App Store, also known as a ânative appâ due to its installation onto the phone itself, has a shelf life of one to two years.  This disparity is due to a variety of factors, including that the software has to be compiled specifically for that operating system, the expense of marketing a native app in hopes of climbing the App Store ladder, and importantly, the backwards compatibility of the JavaScript framework we useâEmber.js. It is noteworthy that this backwards compatibility is what precludes the issues that native apps typically face when new versions are developed, as it is a good demonstration of the webâs design as a platform to endure. On the backend, we employ Phoenix and Elixir, Phoenix being the framework and Elixir being the language. Itâs ironic that the language we use for back end development is called âElixir,â because DockYardâs ingenuity originates from the pursuit of sustainable progress as opposed to the industryâs panacea. &lt;/p&gt;

&lt;p&gt;The experience for employees is no different from DockYardâs approach to design and engineeringâtransparent and uncomplicated. The value placed on communication was echoed during my first meeting with our CEO, Brian. When asked if there was anything I should be sure to do as a new employee, he said: âIf youâre siloed in by yourself, thatâs seen as a failure here.â &lt;/p&gt;

&lt;p&gt;Looking over the past thirty days, I think my biggest fear was feeling embarrassed about my lack of software know-how on top of being a new employee. That being said, my difference in background hasnât made me feel like the albatross of DockYard. Rather, what we have at DockYard is a unique kind of strength that is the result of the inclusion of people from different backgrounds and different skillsets. William Arthur Ward was quoted as saying, âWhen we seek to discover the best in others, we somehow bring out the best in ourselves,â and at least at DockYard, thatâs incredibly true.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building a Space: Chart a Course</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/06/building-a-space-chart-a-course" />
    <id>https://dockyard.com/blog/2016/05/06/building-a-space-chart-a-course</id>
    
    <published>2016-05-06 00:00:00</published>
    <updated>2016-05-13 05:53:16</updated>
    <author><name>Patrick Branigan</name></author>
    <summary>A short series about transforming the DockYard workspace.</summary>
    <content type="html">&lt;p&gt;DockYard has been growing over the past couple years. In 2015 we relocated to a larger space which resulted in a lot of 
creative opportunities internally. âBuilding a Spaceâ is a short series of articles about our successes, failures, and 
lessons learned from stepping outside our comfort zone and designing for a medium we admittedly are not experts in: our 
physical work environment. &lt;/p&gt;

&lt;h2&gt;Reception wall&lt;/h2&gt;

&lt;p&gt;Adjacent to our lobby, divided by our newly built &lt;a href=&quot;https://dockyard.com/blog/2016/05/04/building-a-space-learning-the-ropes&quot; title=&quot;rope wall&quot;&gt;rope wall&lt;/a&gt;, there is our reception area. The previous tenant painted the 
reception wall a vibrant red. It provided a brilliance to the environment that was visually stimulating and aligned with 
their brand colors. However, the walls were painted white prior to our move in, leaving us with a space that lacked character. 
Though white walls made the space feel âclean,â it also made it seem unfinished. The vision for our lobby area already relied 
heavily on a lighter palette so we knew this reception wall was an opportunity for creativity.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/llUDC0k.jpg&quot; alt=&quot;Reception wall&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Challenges and constraints&lt;/h2&gt;

&lt;p&gt;Once a guest walked through our door, the first thing they would encounter was the big blank wall. There wasnât a lot of 
discussion surrounding fixtures for the wall, such as shelving, hanging artwork, or additional lighting. Instead we 
gravitated towards the idea of painting a mural. The question was, what do we paint? Before answering this question, 
there were items to consider. Much like the rope wall, the mural was dependent upon a few considerations.&lt;/p&gt;

&lt;p&gt;First, our team wanted to be able to execute the mural on its own. This would lessen the time and budget needed, but it 
also provided the prospect of working on a project we donât often get the chance to. This resulted increased motivation and 
morale throughout the team. The cost of doing it ourselves equated to the time it would take us (about a week). We found 
that hiring an outside artist would likely put pressure on the budget or the deadline. Plus, weâre imaginative! Weâve all 
painted before! Surely we can rely on our own expertise, right? Weâre designers after all!&lt;/p&gt;

&lt;p&gt;Second, we needed to make sure to maintain a realistic perspective on time and budget without sacrificing our ambition and 
passion for an excellent result. This meant paying close attention to the complexity of executing the piece on the wall. 
Again, much like the rope wall, we hadnât had much recent experience in works of this nature. Paint primer? Whatâs that? 
This didnât hinder our ambition, however. Instead it helped us focus on a single direction.&lt;/p&gt;

&lt;p&gt;That direction was to hand letter the entire mural. We thought painting the mural in our DockYard blue provided a weight 
and simplicity that would counter the existing white space. This color also wouldnât interfere with the personality of the 
letterforms or the message in its entirety. The idea of a lettered piece allowed us to clearly display meaning to our new 
space, our guests and our employees. However, the meaning of the words would prove to be the most complex challenge of them 
all.&lt;/p&gt;

&lt;h2&gt;What to say&lt;/h2&gt;

&lt;p&gt;Initially our design team constructed a list of statements we envisioned on the reception wall. Most had to do with 
welcoming guests or providing inspirational words to entice potential clients. Some options were merely two words in 
length while others were entire quotes from some of historyâs great creative minds. We then consulted with others internally. 
We wanted the statement to be representative of not just designers but also developers, managers, and the entire companyâs 
shared vision. This is when a larger question surfaced.&lt;/p&gt;

&lt;h4&gt;What does this mean to us?&lt;/h4&gt;

&lt;p&gt;What are we trying to accomplish in this space? Does it align with the aspirations and desires of our guests? It turns out 
this wasnât just a greeting to be written on a wall. We were actually touching on a brand element, a mantra that could 
resonate with both our employees and our guests â anyone who entered the office. It had to be something motivating and 
thought-provoking. It had to represent not just our progress as a company but the journeys we take our guests, clients and 
partners on.&lt;/p&gt;

&lt;h2&gt;Chart a course&lt;/h2&gt;

&lt;p&gt;After much more discussion, we landed on âchart a course.â There are many reasons why we believe this is a fitting statement 
for the space.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Uewqtg3.jpg&quot; alt=&quot;Brainstorm&quot;&gt;&lt;/p&gt;

&lt;p&gt;Considering its position and audience it made sense to present something that is instantly digestible in the reception space. 
The statement has the ability to hold different meanings for different audiences, all resembling the idea of progression or 
forward thinking. Charting a course is what we do with clients and employees. We push their adventures and ideas forward, 
whether it be a career or a project. &lt;/p&gt;

&lt;p&gt;Also, like the rope wall, it subtly hints at a nautical theme. Though the nautical theme isnât meant to be at the forefront 
of the entire office experience, it can be delightful to encounter our name, âDockYard,â upon entry and then extend the 
introduction with a corresponding statement such as âchart a courseâ. The name and the statement calmly connect the 
entire entry experience, which may help in a guestâs ability to recall our brand name. &lt;/p&gt;

&lt;h2&gt;How?&lt;/h2&gt;

&lt;p&gt;Where do we start? Sketches of course! We brainstormed multiple compositions, arrangements, letterform weights and styles. 
We played with decoration, shadows and highlights. Here are just a few:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/CvZZxQZ.jpg&quot; alt=&quot;Sketch collage&quot;&gt;&lt;/p&gt;

&lt;p&gt;After reviewing countless sketches and ideas, we discovered one which was particularly engaging to us. The fluidity and 
movement of the letterforms caught our attention. The sequence in size and weight helped guide the eye from start to 
finish. We werenât exactly sold on the arrangement, but it was a great starting point.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/dd8Mh2j.jpg&quot; alt=&quot;Sketch&quot;&gt;&lt;/p&gt;

&lt;p&gt;As with any project, we began to iterate. The piece changed with time for the better. We rearranged the words, and began 
to pronounce a specific brush lettering style. We used tracing paper, pencil and ink to continuously refine the letterforms 
until it satisfied our vision. We then finished refinements on screen.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/h6qNZil.jpg&quot; alt=&quot;Refined sketch&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/zTbGsNT.jpg&quot; alt=&quot;Final sketch&quot;&gt;&lt;/p&gt;

&lt;p&gt;The rest of the process was smooth sailing. We matched our DockYard blue with Behr paint professionals to arrive at a 
color named Secret Society. We used a projector to outline the piece on the reception wall. Lastly we spent hours painting, 
starting with the outlines and finishing with the fills.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/JlE0R0F.jpg&quot; alt=&quot;Paint&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/RsBFfC5.jpg&quot; alt=&quot;Projector&quot;&gt;&lt;/p&gt;

&lt;p&gt;What we ended up with was a beautiful hand lettered mural that has the potential to greet and engage anyone who enters our 
office. Itâs fluid, flexible and, most importantly, it retains a human personality. It doesnât feel manufactured. It 
doesnât speak arbitrarily. It represents the beginning of everything we stand for at DockYard. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/GC3rGpj.jpg&quot; alt=&quot;Final design&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Here&amp;#39;s a look at more of the process:&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/yB1TukV.jpg&quot; alt=&quot;Chris painting&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/tsTz8fp.jpg&quot; alt=&quot;Team painting&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/HEF14PM.jpg&quot; alt=&quot;Finishing touches&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/QsBFWni.jpg&quot; alt=&quot;Tim painting&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/LK656G4.jpg&quot; alt=&quot;Close up&quot;&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building a Space: Learning the Ropes</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/04/building-a-space-learning-the-ropes" />
    <id>https://dockyard.com/blog/2016/05/04/building-a-space-learning-the-ropes</id>
    
    <published>2016-05-04 00:00:00</published>
    <updated>2016-05-13 05:53:37</updated>
    <author><name>Patrick Branigan</name></author>
    <summary>A short series about transforming the DockYard workspace.</summary>
    <content type="html">&lt;p&gt;DockYard has been growing over the past couple years. In 2015 we relocated to a larger space which resulted in a lot of 
creative opportunities internally. âBuilding a Spaceâ is a short series of articles about our successes, failures, and 
lessons learned from stepping outside our comfort zone and designing for a medium we admittedly are not experts in: our 
physical work environment. We start with elements of the lobby area.&lt;/p&gt;

&lt;h2&gt;Our challenge&lt;/h2&gt;

&lt;p&gt;Previously when someone entered our office, theyâd be greeted at the door and instructed to take a seat. Between them and 
the immediate seating area was this curved wall. Theyâd step over it. Theyâd step around it. Theyâd even ask us whether to 
step around it! It was a surprisingly large interruption in the initial experience of visiting the office.&lt;/p&gt;

&lt;p&gt;When building a work space itâs important to ensure the space not only benefits the employee but also prospective clients 
(or really anyone visiting the office). When a guest visits a space there are a lot of moments that leave a lasting 
impression. Having a sign that directs guests where to go impacts a guestâs experience. Greeting guests with a smile as 
they enter the space impacts a guestâs experience. Having a space for guests to queue in while awaiting their meeting impacts 
a guestâs experience. So when a guest enters a space for the first time and is confronted by a curved wall-curb-thing, their 
experience is impacted, likely for worse if they donât know what it is theyâre being confronted with.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/lsnnMrZ.jpg&quot; alt=&quot;Before&quot;&gt;&lt;/p&gt;

&lt;p&gt;What is that?! Well, weâre not completely sure what it is, what it was or what its intended purpose might have been. We 
refer to it as a curved wall yet itâs barely a wall. This was the most immediate challenge. This small curved wall was one 
of the points in the greater project weâve tasked ourselves with: the client experience.&lt;/p&gt;

&lt;p&gt;So how did we go about solving this challenge?&lt;/p&gt;

&lt;h2&gt;Use rope&lt;/h2&gt;

&lt;p&gt;Materials are plentiful in the life of a designer. Paints, inks, brushes, pens, pencils, stock, fabrics, devices, and so on. 
These are typical materials needed perhaps when one is exploring creative outlets, studying for a career in the arts, or 
merely going about their career as a designer. These are our familiar materials when solving a challenge. But how often do 
you see rope used to solve a design challenge? &lt;/p&gt;

&lt;p&gt;Okay, thatâs not a shocking or specific question. Let me rephrase: how often do you see a group of web application designers 
using rope to solve a spatial design challenge?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/fkJyHS4.jpg&quot; alt=&quot;Rope&quot;&gt;&lt;/p&gt;

&lt;p&gt;Rope is potent with creative potential because of its malleability. Its ability to structure complex forms and functions 
was something we believed we could use to our advantage. After all, itâs been used since...forever, and in a seemingly infinite 
amount of scenarios. These characteristics proved beneficial to solving the challenge we were faced with.&lt;/p&gt;

&lt;h2&gt;Why?&lt;/h2&gt;

&lt;p&gt;We pursued this challenge with rope for three primary reasons. First, it provided a boundary between the reception area and 
the lobby area. This was important as it gave both our employees and our guests respective space to tend to their tasks. This 
also allowed for easy communication. With a traditional wall or barrier, one party or the other would have to physically move 
to converse with or greet the other. Instead, a rope wall provides a subtle sense of privacy while still allowing for 
interaction between reception and guests at any given time. It effectively solidified a comfortable space for simply waiting. 
No more guests wandering onto the floor. No more need for reception to reassure the space as a waiting area. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/XFwLxxB.jpg&quot; alt=&quot;Anchoring rope&quot;&gt;&lt;/p&gt;

&lt;p&gt;Secondly, it was achievable with the tools at our disposal and the ambition of our design team. We believed that it was 
completely possible for us to build this wall on our own even though none of us had experience in building such a structure. 
We saved a lot of money purchasing and installing materials ourselves and by using materials we already owned. We also wasted 
no time as we were able to complete the project on our own schedule with time weâd allot to it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/mVRO1Gd.jpg&quot; alt=&quot;Tools&quot;&gt;&lt;/p&gt;

&lt;p&gt;Lastly, it speaks to our brand. Being a raw manila rope, itâs physical qualities suggest  a nautical theme. Aesthetically, 
the ropeâs texture and color complement other items in the space, fitting the overall vision of our DockYard lobby area 
perfectly. We also searched for anchoring hardware that would supplement a subtle nautical theme. This led us to choosing 
eye screws as our anchor hardware. Theyâre unobtrusive, visually satisfying when sequentially ordered, and can be found 
throughout nautical products and scenarios.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/B9v1BpJ.jpg&quot; alt=&quot;Anchors&quot;&gt;&lt;/p&gt;

&lt;h2&gt;How?&lt;/h2&gt;

&lt;p&gt;We approached the project in a way very similar to how we approach any of our web application projects: by researching, 
planning, prototyping, and executing.&lt;/p&gt;

&lt;p&gt;We first gathered inspiration from a variety of sources. We found everything from loosely hanging rope acting as entryway 
drapes, to beautifully anchored, tightly positioned lines of rope acting as entire room dividers. From what we found, we 
knew we wanted our rope wall to use anchored rope and not to be too tightly arranged. This required a bit of prototyping. 
We utilized string and tape to measure and mock the arrangement of the rope.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/hggZLNH.jpg&quot; alt=&quot;Prototype&quot;&gt;&lt;/p&gt;

&lt;p&gt;We then researched how to anchor the rope. As we weighed our options a few considerations became clear. Each vertical piece 
of rope needed to be measured close enough to one another to approximate the curve of the wall. We also realized we couldnât 
anchor individual lines of rope because it would require labor and resources we didnât budget for. These insights informed 
two key decisions. First, each vertically positioned piece of rope needed to be within 4-6 inches from one another which 
happened to align with our prototype measurements. Second, we needed to use one piece of rope to thread the entire wall. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Qw59vJj.jpg&quot; alt=&quot;More anchors&quot;&gt;&lt;/p&gt;

&lt;p&gt;The result? A slightly angled, âtooth shapedâ pattern we love. Itâs clean cut, but itâs movement provides a dynamic unlike 
one weâve come across in terms of rope walls. In more ways than one it not only achieves the goals we began with but also 
provides a variety of interesting perspectives to a space previously in search of an identity. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/c8ntwRi.jpg&quot; alt=&quot;After&quot;&gt;&lt;/p&gt;

&lt;h2&gt;A closer look at the process&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/NPtGps5.jpg&quot; alt=&quot;More prototyping&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/WFidbXt.jpg&quot; alt=&quot;Drilling&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/ciRooiP.jpg&quot; alt=&quot;Screwing&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/USzEKBG.jpg&quot; alt=&quot;Top anchors&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/VuNwOlY.jpg&quot; alt=&quot;Knot&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/vVqxF4g.jpg&quot; alt=&quot;Bottom anchors&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/1VNFFWz.jpg&quot; alt=&quot;More top anchors&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/QG5KbxA.jpg&quot; alt=&quot;Final rope&quot;&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Phoenix Tips and Tricks</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/05/02/phoenix-tips-and-tricks" />
    <id>https://dockyard.com/blog/2016/05/02/phoenix-tips-and-tricks</id>
    
    <published>2016-05-02 00:00:00</published>
    <updated>2016-05-03 19:27:45</updated>
    <author><name>Chris McCord</name></author>
    <summary>Tips and tricks to keep your phoenix code clean and concise</summary>
    <content type="html">&lt;p&gt;As newcomers get up and running quickly with Phoenix, we see folks hit a few common issues that they can cleanly solve with a few simple tips.&lt;/p&gt;

&lt;h3&gt;Override &lt;code&gt;action/2&lt;/code&gt; in your controllers&lt;/h3&gt;

&lt;p&gt;Often times, you&amp;#39;ll find yourself repeatedly needing to access connection information in your controller actions, such as &lt;code&gt;conn.assigns.current_user&lt;/code&gt; or similarly reaching deeply into nested connection information. This can become tedious and obscures the code. While we could extract the lookup to a function, such as &lt;code&gt;current_user(conn)&lt;/code&gt;, then we are needlessly performing extra map access when we only need to do the lookup a single time. There&amp;#39;s a better way.&lt;/p&gt;

&lt;p&gt;Phoenix controllers all contain an &lt;code&gt;action/2&lt;/code&gt; plug, which is called last in the controller pipeline. This plug is responsible for calling the function specified in the route, but Phoenix makes it overridable so you can customize your controller actions. For example, imagine the following controller:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule MyApp.PostController do
  use MyApp.Web, :controller

  def show(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id}) do
    {:ok, post} = Blog.get_post_for_user(conn.assigns.current_user, id)
    render(conn, &amp;quot;show.html&amp;quot;, owner: conn.assigns.current_user, post: post)
  end

  def create(conn, %{&amp;quot;post&amp;quot; =&amp;gt; post_params}) do
    {:ok, post} = Blog.publish_post(conn.assigns.current_user, post_params)
    redirect(conn, to: user_post_path(conn, conn.assigns.current_user, post)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Not terrible, but the repeated &lt;code&gt;conn.assigns.current_user&lt;/code&gt; access gets tiresome and obscures what we care about, namely the &lt;code&gt;current_user&lt;/code&gt;. Let&amp;#39;s override &lt;code&gt;action/2&lt;/code&gt; to see how we can clean this up:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule MyApp.PostController do
  use MyApp.Web, :controller

  def action(conn, _) do
    args = [conn, conn.params, conn.assigns[:current_user] || :guest]
    apply(__MODULE__, action_name(conn), args)
  end

  def show(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id}, current_user) do
    {:ok, post} = Blog.get_post_for_user(current_user, id)
    render(conn, &amp;quot;show.html&amp;quot;, owner: current_user, post: post)
  end

  def create(conn, %{&amp;quot;post&amp;quot; =&amp;gt; post_params}, current_user) do
    {:ok, post} = Blog.publish_post(current_user, post_params)
    redirect(conn, to: user_post_path(conn, current_user, post)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Much nicer. We simply overrode &lt;code&gt;action/2&lt;/code&gt; on the controller, and modified the arities of our controller actions to include a new third argument, the &lt;code&gt;current_user&lt;/code&gt;, or &lt;code&gt;:guest&lt;/code&gt; if we aren&amp;#39;t enforcing authentication. If we want to apply this to multiple controllers, we can extract it to a &lt;code&gt;MyApp.Controller&lt;/code&gt; module:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule MyApp.Controller do
  defmacro __using__(_) do
    quote do
      def action(conn, _), do: MyApp.Controller.__action__(__MODULE__, conn)
      defoverridable action: 2
    end
  end

  def __action__(controller, conn) do
    args = [conn, conn.params, conn.assigns[:current_user] || :guest]
    apply(controller, Phoenix.Controller.action_name(conn), args)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now any controller that wants to use our modified actions can &lt;code&gt;use MyApp.Controller&lt;/code&gt; on a case-by-case basis. We also made sure to make &lt;code&gt;action/2&lt;/code&gt; overridable again to allow caller&amp;#39;s downstream to customize their own behavior.&lt;/p&gt;

&lt;h3&gt;Rendering the &lt;code&gt;ErrorView&lt;/code&gt; directly&lt;/h3&gt;

&lt;p&gt;Most folks use their &lt;code&gt;ErrorView&lt;/code&gt; to handle rendering exceptions after they are caught and translated to the proper status code, such as a &lt;code&gt;Ecto.NoResultsError&lt;/code&gt; rendering the &amp;quot;404.html&amp;quot; template or a &lt;code&gt;Phoenix.ActionClauseError&lt;/code&gt; rendering the &amp;quot;400.html&amp;quot; template. What many miss is the fact that the &lt;code&gt;ErrorView&lt;/code&gt; is just like any other view. It can and should be called directly to render responses for your error cases rather than relying on exceptions for all error possibilities. For example, imagine handling the error cases for our &lt;code&gt;PostController&lt;/code&gt; in the previous example:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def create(conn, %{&amp;quot;post&amp;quot; =&amp;gt; post_params}, current_user) do
  with {:ok, post} &amp;lt;- Blog.publish_post(current_user, post_params) do
    redirect(conn, to: user_post_path(conn, current_user, post)
  else
    {:error, %Ecto.Changeset{} = changeset} -&amp;gt; render(conn, &amp;quot;edit.html&amp;quot;, changeset: changeset)
    {:error, :unauthorized} -&amp;gt;
      conn
      |&amp;gt; put_status(401)
      |&amp;gt; render(ErrorView, :&amp;quot;401&amp;quot;, message: &amp;quot;You are not authorized to publish posts&amp;quot;)
    {:error, :rate_limited} -&amp;gt;
      conn
      |&amp;gt; put_status(429)
      |&amp;gt; render(ErrorView, :&amp;quot;429&amp;quot;, message: &amp;quot;You have exceeded the max allowed posts for today&amp;quot;)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here we&amp;#39;ve used the Elixir 1.3 &lt;code&gt;with/else&lt;/code&gt; expressions. Note how we are able to succinctly send the 401 and 429 responses by directly rendering our &lt;code&gt;ErrorView&lt;/code&gt;. We also passed the template name as an atom, such as &lt;code&gt;:&amp;quot;401&amp;quot;&lt;/code&gt; so our template will be rendered based on the accept headers such as &lt;code&gt;&amp;quot;401.json&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;404.html&amp;quot;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Avoid Task.async if you don&amp;#39;t plan to Task.await&lt;/h3&gt;

&lt;p&gt;Elixir Tasks are great for cheap concurrency and parallelizing bits of work, but we often see &lt;code&gt;Task.async&lt;/code&gt; used incorrectly. The most important thing to realize is that the caller is linked to the task. This means that if the task crashes, the caller does as well, and vice-versa. For example, the following code is perfectly fine because we await both tasks and we expect to crash if they fail:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def create(conn, %{&amp;quot;access_code&amp;quot; =&amp;gt; code}) do
  facebook = Task.async(fn -&amp;gt; Facebook.get_token(code) end)
  twitter  = Task.async(fn -&amp;gt; Twitter.get_token(code) end)

  render(conn, &amp;quot;create.json&amp;quot;, facebook: Task.await(facebook),
                              twitter: Task.await(twitter))
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this case, we want to fetch a token from Facebook and Twitter, and we can do this work in parallel since the tasks are not coupled in any way. When rendering our JSON response for the client, we can await both tasks and send the response back. This use of &lt;code&gt;Task.async&lt;/code&gt; and &lt;code&gt;Task.await&lt;/code&gt; is just fine, but now imagine another case where we want to fire off a quick task and immediately respond to the client.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def delete(conn, _, current_user) do
  {:ok, user} = Accounts.cancel_account(current_user)
  Task.async(fn -&amp;gt; Audits.alert_cancellation_notice(user) end)

  conn
  |&amp;gt; signout()
  |&amp;gt; put_flash(:info, &amp;quot;So sorry to see you go!&amp;quot;)
  |&amp;gt; redirect(to: &amp;quot;/&amp;quot;)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this case, we want to notify our staff about an account cancellation, say by sending an email, but we don&amp;#39;t want the client to wait on this particular work. It might feel natural to use &lt;code&gt;Task.async&lt;/code&gt; here, but since we aren&amp;#39;t awaiting the result and the client isn&amp;#39;t concerned about its success, we have an issue. First, we are linked to the caller, so any abnormal exit on either side will crash the other. The client could get a 500 error after their account has been canceled and not be sure if their operation was successful. Likewise, our staff notice could be brought down by an error when sending the response, preventing our staff being alerted of the completed event. We can use &lt;code&gt;Task.Supervisor&lt;/code&gt; and its &lt;code&gt;async_nolink&lt;/code&gt; to achieve an offloaded process that is isolated under its own supervision tree.&lt;/p&gt;

&lt;p&gt;First, we&amp;#39;d need to add our own &lt;code&gt;Task.Supervisor&lt;/code&gt;, to our supervision tree, in &lt;code&gt;lib/my_app.ex&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;children = [
  ...,
  supervisor(Task.Supervisor, [[name: MyApp.TaskSupervisor]])
]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, we can now offload the task to our supervisor. We&amp;#39;ll also use the &lt;code&gt;async_nolink&lt;/code&gt; function to isolate the task from the caller:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def delete(conn, _, current_user) do
  {:ok, user} = Accounts.cancel_account(current_user)
  Task.Supervisor.async_nolink(MyApp.TaskSupervisor, fn -&amp;gt;
    Audits.alert_cancellation_notice(user) end)
  end)

  conn
  |&amp;gt; signout()
  |&amp;gt; put_flash(:info, &amp;quot;So sorry to see you go!&amp;quot;)
  |&amp;gt; redirect(to: &amp;quot;/&amp;quot;)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now our task is properly offloaded to its own supervisor who will take care of any failures and proper logging. Likewise, any crash in the task, or the controller, won&amp;#39;t affect the other.&lt;/p&gt;

&lt;p&gt;With these tips, you&amp;#39;ll keep your code clean and to the point, and isolated when required.&lt;/p&gt;
</content>
  </entry><entry>
    <title>EmberConf 2016 Recap</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/29/ember-conf-recap" />
    <id>https://dockyard.com/blog/2016/04/29/ember-conf-recap</id>
    
    <published>2016-04-29 00:00:00</published>
    <updated>2016-04-29 19:32:20</updated>
    <author><name>Marten Schilstra</name></author>
    <summary>The Year of Progress and Progressive Web Apps</summary>
    <content type="html">&lt;p&gt;Last year&amp;#39;s &lt;a href=&quot;http://emberconf.com&quot;&gt;EmberConf&lt;/a&gt; was a conference packed with exciting new things.
The Ember 2.0 release was closing in. A lot of 1.0s of big Ember projects would
be shipped soon. &lt;a href=&quot;http://www.ember-fastboot.com&quot;&gt;FastBoot&lt;/a&gt; was announced and so was &lt;a href=&quot;https://github.com/tildeio/glimmer&quot;&gt;Glimmer&lt;/a&gt;.
Our new rendering engine got on par with React&amp;#39;s blazingly fast
rendering engine. There was a lot of hype and excitement.&lt;/p&gt;

&lt;p&gt;This year the atmosphere of the conference was different. Not a bad different
per se, but different. This year felt as if we had just completed major goals
set out at last year&amp;#39;s conference, and that we were now on track to keep leveling
up those achievements in the foreseeable future.&lt;/p&gt;

&lt;p&gt;For example, Glimmer II drastically improves upon Glimmer I. The 60fps
rendering demo was mind blowing, but it felt different from seeing for the
first time how comically bad the rendering engine was before Glimmer 1.0 and then
see it run as fast as React&amp;#39;s rendering engine. It was already expected
that Glimmer II would improve upon Glimmer I.&lt;/p&gt;

&lt;p&gt;There is one big new movement this year. It is the movement of
&lt;a href=&quot;https://developers.google.com/web/progressive-web-apps?hl=en&quot;&gt;Progressive Web Apps&lt;/a&gt; (&lt;em&gt;PWA&lt;/em&gt;). FastBoot 1.0 will be released soon and
there are a bunch of other exciting projects putting effort into pairing up
Ember with &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/service-worker/introduction/&quot;&gt;ServiceWorkers&lt;/a&gt; and other PWA tools that (recently) have been added
to (mobile) browsers.&lt;/p&gt;

&lt;p&gt;Because of these developments I would like to dub this year:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Year of Progress and Progressive Web Apps&amp;quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is another thing I want to mention: &lt;a href=&quot;http://chrislopresto.com/presentations/living-style-guide-driven-development?c=false&amp;amp;h=0&amp;amp;ph=900&amp;amp;pw=1600&amp;amp;v=0&quot;&gt;Living Styleguides&lt;/a&gt;.
Chris LoPresto gave a talk about this. I did not yet know of this movement
until Luke Melia told me I should go see Chris&amp;#39; talk. It was supposed to be
awesome. I&amp;#39;m glad I followed Luke&amp;#39;s advice and went to see Chris&amp;#39; talk.
You may think that styleguides are for designers, but the way these styleguides
are built will actually help developers architect better components.&lt;/p&gt;

&lt;p&gt;I had a really good time at EmberConf 2016. I&amp;#39;m excited to start trying out Living
Styleguides at DockYard. We&amp;#39;re already using &lt;a href=&quot;https://dockyard.com/blog/2016/03/29/served-with-fastboot-again&quot;&gt;FastBoot&lt;/a&gt; and we&amp;#39;re
also actively experimenting with Progressive Web App technology.&lt;/p&gt;

&lt;p&gt;I look forward to another round of talks that show how the Ember ecosystem has been
improved and solidified in 2017. Also to meet all the wonderful people I&amp;#39;ve met this
year again.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Choosing a Strategy + Design Partner</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/26/choosing-strategy-design-partner" />
    <id>https://dockyard.com/blog/2016/04/26/choosing-strategy-design-partner</id>
    
    <published>2016-04-26 00:00:00</published>
    <updated>2016-04-28 20:29:47</updated>
    <author><name>Mark Kaplan</name></author>
    <summary>It can be hard to tell agencies apart. Strategy can make all the difference. Learn how to spot a strategic agency.</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/iHgcgzh.jpg&quot; alt=&quot;Mad Men Barbie Dolls&quot;&gt;
&lt;/br&gt;Image Credit: &lt;a href=&quot;http://www.amc.com/shows/mad-men/extras/mad-men-barbie-dolls#/1&quot;&gt;AMC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Youâre interviewing candidates for an opening on your team. Youâre torn between two finalists. Each has deep skills and experience, comes with solid references, and would increase diversity. In both a subjective or objective evaluation, theyâd be equal.&lt;/p&gt;

&lt;p&gt;How can you make such an important decision, without resorting to a coin flip?  &lt;/p&gt;

&lt;p&gt;Choosing a partner for strategy and design of web applications is a lot like hiring that new team member. Every agency youâll meet will tell you about their services and âThe Process.â Theyâll share a cloud of client logos and case studies with slick creative and impressive results. Their offices will be way more hip than yours. Youâll be shown a photo of a designer pointing to a wall of design artifacts.&lt;/p&gt;

&lt;p&gt;With every agency pitching what can feel like the same experience and capabilities, how do you choose?  &lt;/p&gt;

&lt;p&gt;&lt;/br&gt;&lt;/p&gt;

&lt;h2&gt;The Client Should Always Come First&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;âA gossip talks about other people. A bore talks about himself. A brilliant conversationalist talks to you about yourself.â&lt;/br&gt;&lt;/br&gt;âUnknown&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a similar vein, an agency that understands the importance of objectives in design will move quickly from talking about their reputation, to a deeper conversation about you and your business goals. Theyâll get excited about what could be accomplished together. &lt;/p&gt;

&lt;p&gt;Do the memebers of the team seem interested in listening to you, and learning from you?  Are they focused on trult understanding the problems, rather than jumping to their favored solutions?  &lt;/p&gt;

&lt;p&gt;Are they asking deep questions about your goals?  Your past successes and failures?  Your personal situation? They should regard their job as not only to deliver what you want and need but also to make you look good.
&lt;/br&gt;&lt;/p&gt;

&lt;h2&gt;Become Comfortable by Being Uncomfortable&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;âIf it scares you, it might be a good thing to try.â&lt;/br&gt;&lt;/br&gt;âSeth Godin&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you answer the agencyâs questions, also pay attention to the kinds of questions they ask. Are they making you uncomfortable with some of those questions? Thatâs OK.  &lt;/p&gt;

&lt;p&gt;Sometimes the most important questions are uncomfortable because they challenge some sacred-cow assumptions. They may force you to reconsider things that really need fixing. Being hopeful that stuff will work out is the opposite of strategy. Itâs always better to know â or at least to be less uncertain. &lt;/p&gt;

&lt;p&gt;Strategic designers routinely chart a course through uncertain seas. They should be comfortable being uncomfortable and they should help you feel the same way. Rather than being taken aback, take a shot at answering those questions.
&lt;/br&gt;&lt;/p&gt;

&lt;h2&gt;Direct vs. Indirect Experience&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;âExperience is simply the name we give our mistakes.â&lt;/br&gt;&lt;/br&gt;âOscar Wilde&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A claim of âexperienceâ is no guarantee of a favorable outcome. Experience is a set of responses to particular business problems (not yours), in particular contexts (not yours, either). Thatâs why duplicating a successful companyâs business model or solution rarely works out. Despite what best-selling business books seem to suggest, thereâs no single recipe for success. Every challenge is fresh, and every solution begins with a blank page.&lt;/p&gt;

&lt;p&gt;If an agency claims direct experience in your industry, ask to also see examples of how they solved problems like yours for clients in other industries. Have they worked through problems of similar scale or complexity?&lt;/p&gt;

&lt;p&gt;There are scenarios where specialized experience does matter. This is particularly true in industries that are highly-regulated or highly-competitive. If having specific domain knowledge on your project is important, discuss that. For example, if youâre a pharma brand with a âblack box warningâ on your product, youâd ask about their understanding of the specific FDA rules.&lt;/p&gt;

&lt;p&gt;In some cases, an agencyâs lack of direct experience can be an asset rather than a liability. Sometimes distance makes things clearer. This is especially true for an industry or company that tends to be a technology laggard. Expect to hear pushback on phrases like, âWeâve always done it that wayâ or âThat would never work here.â  Itâs likely theyâve met similar resistance elsewhere â and overcome it.
&lt;/br&gt;&lt;/p&gt;

&lt;h2&gt;Experts Are Made, Not Born&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;âAn expert is someone who tells you why you canât do something.â&lt;/br&gt;&lt;/br&gt;âSir Alec Issigonis, designer of the Morris Mini (predecessor to the Mini Cooper)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An agency should be able to show how fast they can learn your business. Even in the earliest meetings, they should bring insights and a pain hypothesis. Theyâre outsiders to your private domain, so the attempt means more than getting the details right. &lt;/p&gt;

&lt;p&gt;Look for evidence for how an agency leverages âabductive reasoning,â which is the seemingly magical ability to synthesize what theyâve learned into actionable insights and design ideas. They should tap both personal and institutional knowledge and apply it to new learnings about your circumstances.&lt;/p&gt;

&lt;p&gt;A rich set of design-thinking tools and methods will enable the agency to wrap their heads around the unfamiliar. Ask them not just which problems theyâve solved but also how they learn and share knowledge.
&lt;/br&gt;&lt;/p&gt;

&lt;h2&gt;Itâs Decision Time&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;âTrust yourself, you know more than you think you think you do.â&lt;/br&gt;&lt;/br&gt;âDr. Benjamin Spock&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Like hiring the right team member, finding the right agency partner is as much about &lt;em&gt;who they are&lt;/em&gt; as &lt;em&gt;what they know&lt;/em&gt;. To ensure a good fit, the agency should care as much about figuring out if youâre a good client for them, as you do figuring out if theyâre a good agency for you.&lt;/p&gt;

&lt;p&gt;Donât look for an agency who claims they can solve all your problems. Look for one who will face them with you.&lt;/p&gt;
</content>
  </entry><entry>
    <title>A learning experience in web application design (part 2 of 2)</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/20/a-learning-experience-in-web-application-design-part-2" />
    <id>https://dockyard.com/blog/2016/04/20/a-learning-experience-in-web-application-design-part-2</id>
    <category term="design" label="Design"/><category term="design-process" label="Design Process"/><category term="design-thinking" label="Design Thinking"/>
    <published>2016-04-20 00:00:00</published>
    <updated>2016-04-20 20:41:24</updated>
    <author><name>Chris Bowers</name></author>
    <summary>A speculative project that challenged me to fully consider a range of interface states.</summary>
    <content type="html">&lt;p&gt;In my &lt;a href=&quot;https://dockyard.com/blog/2016/03/11/a-learning-experience-in-web-application-design-part-1&quot;&gt;last post&lt;/a&gt;, I described Sprout Pass, a speculative project for a web application that would deliver fresh local produce right to oneâs doorstep. Sprout Pass is inspired and informed by the idea of community-supported agriculture, also known as farm sharing. Sprout Pass would facilitate orders and delivery between users and their local farmers. &lt;/p&gt;

&lt;p&gt;Users need a UI they can trust and enjoy, especially for a perishable product like produce.  Coming to DockYard from a background in print design, I wanted to explore how an interface provides user support. An interface communicates with a user through feedback and component states, which have the potential to build trust and positive experiences. I consolidated my exploration, planning, and research to focus on the visual UI design. To cover my bases, I designed component screens with a broad range of associated states. &lt;/p&gt;

&lt;p&gt;My first consideration for the app&amp;#39;s visual design was its color selection. Produce delivery applications arenât exactly a flooded market, so while green might be an âobviousâ choice, it was a viable branding option. I chose a positive green thatâs closer to blue than yellow to avoid an overly acidic aesthetic. For the typography, I relied on the humanist sans serif Whitney, because the heavier weights of this typeface have an honest and friendly tone that establish the personality of Sprout Pass. Let&amp;#39;s go through a few examples of different states an interface can be in. &lt;/p&gt;

&lt;h2&gt;Before a user does anything&lt;/h2&gt;

&lt;p&gt;Every introduction has the potential to start a new, meaningful relationship. Before subscribing, a user must know what Sprout Pass can do to enhance their quality of life. The introduction for Sprout Pass allows the user to swipe through as much of the content as they want while always providing a path to sign up or login. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/FtLpVfM.png&quot; alt=&quot;sp_01&quot;&gt;&lt;/p&gt;

&lt;p&gt;Background photo credit: &lt;a href=&quot;https://unsplash.com/photos/4R1YpmGO52I&quot;&gt;Sven Scheuermeier&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Confirmation &amp;amp; errors&lt;/h2&gt;

&lt;p&gt;Confirmations and errors will dynamically appear next to input fields, to reassure the user of their progress as they work on the form. For questions that require more thought on the user&amp;#39;s part, inline validation messages can help people complete web forms faster and with less effort. If youâd like a more detailed reference for when to show inline validation, Luke Wroblewski &lt;a href=&quot;http://alistapart.com/article/inline-validation-in-web-forms&quot;&gt;tested inline validation&lt;/a&gt; against the submit-and-refresh model. &lt;/p&gt;

&lt;p&gt;For this sign up, both input states use color and icons to identify and distinguish themselves without being overly dramatic. The brand color is a saturated green, which correlates with correct and positive states. The submit button would turn this color when every validation has been satisfied. &lt;/p&gt;

&lt;p&gt;Error states are a necessary part of any application, but the language and form of them is often overlooked. The brandâs personality should manifest itself through all bits of copy, even the error states. Negativity and blame in error states doesnât contribute to a successful application experience. For the invalid email example, Sprout Pass takes the blame for the error and offers a solution. Model applications like MailChimp and Tumblr maintain a charming personality while doing this as well. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/duEZdAS.png&quot; alt=&quot;sp_02&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Empty state | An existing component with no data&lt;/h2&gt;

&lt;p&gt;New users typically love to poke around before making any purchases or commitments, but Sprout Pass initially wonât have any data to fill its various components. Engaging and informative empty states support this behavior, and can lead to greater customer retention. Other instances of empty states can exist when a user clears the data or an error occurs. When a new user opens Sprout Pass, there wonât be much to show them at first, but they can still be engaged.  A successful empty state will delight, educate, and motivate the user to add information and interact with the app. In this empty state, a bit of copy identifies what will eventually exist, and the vibrant green button is used as direction.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/0v94ZqZ.png&quot; alt=&quot;sp_03 + sp_04&quot;&gt;&lt;/p&gt;

&lt;p&gt;Background photo credit: &lt;a href=&quot;https://unsplash.com/photos/rHbob_bEsSs&quot;&gt;Matt Benson&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Done | Ensuring a successful transaction&lt;/h2&gt;

&lt;p&gt;To reassure the user of their order completion, the brand color overtakes the screen for a positive order confirmation. The color and icon, consistent with the completed state, combine to substantiate the order confirmation. This screen also prompts the user with two paths forward. This keeps the user engaged while the application is in between waiting for and scheduling packages.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/wI2iN9u.png&quot; alt=&quot;sp_05 + sp_06&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Ideal state&lt;/h2&gt;

&lt;p&gt;The completed package screen is where most users will become more familiar with the application. They will see this section for the longest amount of time, unlike some of the other states that will be viewed only for a few moments. The selection process and empty state have prepared the user for this level of complexity. Because the primary objective of this product is a delivery service, the status of the next delivery is most prominent. This screen updates to track delivery progress, and the editing function becomes inactive 48 hours before deliveries. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/JUVj8sQ.png&quot; alt=&quot;sp_07 + sp_08&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Too much | Managing full data sets&lt;/h2&gt;

&lt;p&gt;When the past orders history exceeds the set limit of five items, this state identifies quantity and provides access to the full dataset. The user is going to want to know how much more history there is available to them.  If the quantity and navigation of your data isn&amp;#39;t intuitive, a too much state can be very frustrating. This Sprout Pass content is condensed and limited by time, so the full history does not require pagination.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/zyIrMiE.png&quot; alt=&quot;sp_09&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;Exploring Sprout Pass helped me develop a familiarity with interface states that I admittedly would have overlooked. After understanding the value and characteristics for each state, I was able to apply my knowledge of visual systems and hierarchy. Every state of a web application component is integral to a userâs positive experience and should be designed with intention. Thoughtfully designed interface states will reduce the risk of confusing or surprising a user, and all of these states work together to make a streamlined experience. &lt;/p&gt;
</content>
  </entry><entry>
    <title>Is it time to call a designer?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/19/is-it-time-to-call-a-designer" />
    <id>https://dockyard.com/blog/2016/04/19/is-it-time-to-call-a-designer</id>
    <category term="design" label="Design"/><category term="ux-design" label="Ux Design"/><category term="business" label="Business"/><category term="design-strategy" label="Design Strategy"/>
    <published>2016-04-19 00:00:00</published>
    <updated>2016-04-21 13:42:01</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Since its beginnings in the 1800s, design as a profession has grown to the point that it now touches almost every aspect of our lives. But we still often assume itâs just about decoration.</summary>
    <content type="html">&lt;p&gt;There is an old fable about a philosopher. A baby was born, and the parents presented the baby to the philosopher in their city at the age of just one month. They apologized for being so early, and asked for advice on how to best plan for an education so the baby would grow up as a proper citizen. To which the philosopher replied - âYouâre not too early. You are ten months late.â&lt;/p&gt;

&lt;p&gt;I could not track down a proper source for this - most likely itâs an ancient Confucian fable. But I always come back to it when I plan and schedule design work. The moral of it keeps coming to mind: âyou thought it was too early, but itâs best to start even earlier.â&lt;/p&gt;

&lt;h2&gt;Why we think âitâs too earlyâ to add design&lt;/h2&gt;

&lt;p&gt;In fact, many people have the understanding of what design can do for business based on a historical truth. The value (and timing) for design seems closely tied to the idea of decoration and the value it could add to mass produced consumer products. This understanding is rooted in the late 1800s, when adding decorative elements to mass produced consumer goods made them more attractive to the public. The decoration helped increase sales from what people practically needed and drove consumer demand based on a desire for updated styles.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/nqrP5EE.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mass production allowed for âdesignedâ (but actually decorated) consumer products to be widely available at the turn of the last century.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;The other jobs of design&lt;/h2&gt;

&lt;p&gt;I often hear a similar âdecorativeâ understanding of design when I talk to people about what my job is today. At the recent MIT Ideas &lt;a href=&quot;http://globalchallenge.mit.edu/&quot;&gt;Global Challenge&lt;/a&gt;, hosted at the Media Lab, I talked to several of the teams about their goals, and UX design. All the teams were very enthusiastic, but in every conversation I heard the phrase âonce we finish X technology, weâll be ready for designâ¦â This phrase reveals an assumption that design is something you might apply on top of an existing product or service, once itâs almost finished.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/ao0QwB0.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;MIT Ideas Global Challenge presentations event in April 2016&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The way to think about what design can do for business, in fact, is almost exactly the opposite. Applying design - specifically, design thinking - at the inception of a project will allow for the greatest impact.&lt;/p&gt;

&lt;h2&gt;Why start with design&lt;/h2&gt;

&lt;p&gt;Design today is well adapted to dealing with unknowns, considering the big picture, and proposing a way forward. You can name specific steps, such as design research, user experience design, and user story development - or keep everything under the bigger umbrella of âdesignâ. But it is the ability to start early (before everything is known) and move forward in an iterative manner (by testing and improving) that makes design impactful at the early stages of a product or service.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/YNN6FhV.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Business leaders are well aware of the value visual design can bring to their products. But strategic design, applied early in the life of a project, is often a missed opportunity. To get the best value from the latest design practices, consider it early, and bring a designer to the table at the first stages of product strategy. &lt;/p&gt;

&lt;p&gt;For a deeper look into the relationship between design &amp;amp; business, check out John Maedaâs &lt;a href=&quot;http://www.kpcb.com/blog/design-in-tech-report-2016&quot;&gt;Design in Tech report&lt;/a&gt;. In it, he presents compelling proof of the value design brings, and predicts the top three directions in which design will experience the most growth over the next year.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember: Declarative Templating with Composable Helpers</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/18/ember-composable-helpers" />
    <id>https://dockyard.com/blog/2016/04/18/ember-composable-helpers</id>
    <category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/><category term="addon" label="Addon"/>
    <published>2016-04-18 00:00:00</published>
    <updated>2016-04-21 16:51:25</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Use small, composable helpers to power up your templates.</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://dockyard.com/blog/2016/02/19/best-practices-route-actions&quot;&gt;Previously&lt;/a&gt;, I mentioned that Ember&amp;#39;s new &lt;code&gt;Helper&lt;/code&gt; implementation landed in &lt;a href=&quot;http://emberjs.com/blog/2015/06/12/ember-1-13-0-released.html#toc_new-ember-js-helper-api&quot;&gt;1.13&lt;/a&gt;. In my opinion, helpers are one of the most useful, yet least talked about features in Ember.&lt;/p&gt;

&lt;p&gt;In my EmberConf 2016 talk (&lt;a href=&quot;https://www.youtube.com/watch?v=lP9ap-AKBAM&amp;amp;list=PL4eq2DPpyBblc8aQAd516-jGMdAhEeUiW&quot;&gt;video&lt;/a&gt;) on Idiomatic Ember, I spoke about helpers in detail, showing how they can be used to power up and essentially extend &lt;a href=&quot;http://handlebarsjs.com/&quot;&gt;Handlebars&lt;/a&gt; with custom functionality. These helpers can then be used to allow declarative templating - a style of templating by composing actions, and giving templates more responsibility with regards to presentational logic.&lt;/p&gt;

&lt;p&gt;Together with fellow DockYarder &lt;a href=&quot;https://twitter.com/Martndemus&quot;&gt;Marten Schilstra&lt;/a&gt;, we&amp;#39;ve created the &lt;a href=&quot;https://github.com/DockYard/ember-composable-helpers&quot;&gt;ember-composable-helpers&lt;/a&gt; addon. It&amp;#39;s a package of declarative helpers that lend themselves naturally for composition, and using it can help remove boilerplate code in your app. You can install it today with:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ember install ember-composable-helpers
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;One of my favorite helpers in the addon is the &lt;code&gt;pipe&lt;/code&gt; helper (and its closure action cousin, &lt;code&gt;pipe-action&lt;/code&gt;). This lets you declaratively compose actions in your template, instead of creating many variants in your Component:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{perform-calculation
    add=(action &amp;quot;add&amp;quot;)
    subtract=(action &amp;quot;subtract&amp;quot;)
    multiply=(action &amp;quot;multiply&amp;quot;)
    square=(action &amp;quot;square&amp;quot;)
}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! perform-calculation/template.hbs }}
&amp;lt;button {{action (pipe add square) 2 4}}&amp;gt;Should be 36&amp;lt;/button&amp;gt;
&amp;lt;button {{action (pipe subtract square) 4 2}}&amp;gt;Should be 4&amp;lt;/button&amp;gt;
&amp;lt;button {{action (pipe multiply square) 5 5}}&amp;gt;Should be 625&amp;lt;/button&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This pipe helper was inspired by Elixir&amp;#39;s pipe operator (&lt;code&gt;|&amp;gt;&lt;/code&gt;), which lets you write the following:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;A(B(C(D(E), &amp;quot;F&amp;quot;), &amp;quot;G&amp;quot;), &amp;quot;H&amp;quot;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As a series of data transforms:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;E
|&amp;gt; D()
|&amp;gt; C(&amp;quot;F&amp;quot;)
|&amp;gt; B(&amp;quot;G&amp;quot;)
|&amp;gt; A(&amp;quot;H&amp;quot;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Using the pipe operator, we can naturally express how &lt;code&gt;E&lt;/code&gt; is passed to the &lt;code&gt;D&lt;/code&gt; function, then the return value of that function is passed into &lt;code&gt;C&lt;/code&gt; as its first argument, and so on. I think we can agree that the pipe version is a lot easier to read!&lt;/p&gt;

&lt;h2&gt;If only you knew the power of the Helper&lt;/h2&gt;

&lt;p&gt;You can think of a helper as a primitive &lt;code&gt;KeyWord&lt;/code&gt; construct used by Ember and HTMLBars to extend the ordinary expressions provided by Handlebars. At its most basic level, the Handlebars library is responsible for compiling the &lt;code&gt;hbs&lt;/code&gt; language down to HTML:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;p&amp;gt;{{myText}}&amp;lt;/p&amp;gt;
&amp;lt;!-- compiles down to: --&amp;gt;
&amp;lt;p&amp;gt;Hello world!&amp;lt;/p&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Ember and HTMLBars then builds on top of this, adding useful keywords like &lt;code&gt;action&lt;/code&gt;, &lt;code&gt;mut&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, and &lt;code&gt;hash&lt;/code&gt;. In fact, all the familiar keywords you&amp;#39;ve been using (everything from &lt;code&gt;each&lt;/code&gt; to &lt;code&gt;component&lt;/code&gt;) are &lt;a href=&quot;http://emberjs.com/api/classes/Ember.Templates.helpers.html&quot;&gt;actually HTMLBars helpers under the hood&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Ember Helpers operate at a higher level compared to HTMLBars helpers, but can also be used as a way to let you create new keywords in Ember, effectively allowing you to extend templating with custom behavior.&lt;/p&gt;

&lt;h2&gt;It depends&lt;/h2&gt;

&lt;p&gt;More experienced or conservative developers might see this as a red flag: while making this framework construct available to end-users is useful, it can also open up potential for abuse. &lt;/p&gt;

&lt;p&gt;For example, in Elixir, macros can be used to extend the language, but aren&amp;#39;t recommended unless you &lt;em&gt;really&lt;/em&gt; need to. In fact, this has been informally codified in the excellent &lt;a href=&quot;https://pragprog.com/book/cmelixir/metaprogramming-elixir&quot;&gt;Metaprogramming Elixir&lt;/a&gt; book by &lt;a href=&quot;https://twitter.com/chris_mccord&quot;&gt;Chris McCord&lt;/a&gt; â &amp;quot;Rule 1: Don&amp;#39;t Write Macros&amp;quot;.&lt;/p&gt;

&lt;p&gt;Fortunately, helpers aren&amp;#39;t quite as powerful as Elixir macros, and play an important role in the Ember programming model. Unlike a macro, which lets you reach down to the AST, using an Ember helper to extend presentational logic is OK &lt;em&gt;as long as we don&amp;#39;t abuse it&lt;/em&gt;, and that distinction is where experience comes into play. So use helpers responsibly.&lt;/p&gt;

&lt;h2&gt;Get your logic off my lawn&lt;/h2&gt;

&lt;p&gt;Some people may feel uneasy using addons containing helpers because of the misconception that it introduces too much logic in their templates, and that they prefer to keep their templates logic-free.&lt;/p&gt;

&lt;p&gt;As a best practice, we should strive not to have complicated logic in our templates, and when your sub-expression looks like this:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#unless (or (and (gte value 0) (lt value 0.0001))
              (and (lt value 0) (not allowNegativeResults)))}}
  ...
{{/unless}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s a sign that you&amp;#39;re better off using a computed property. &lt;/p&gt;

&lt;p&gt;On the other hand, keeping your templates 100% logic-free is really hard â you&amp;#39;re likely already using a logical helper like &lt;code&gt;if/else&lt;/code&gt; or &lt;code&gt;unless&lt;/code&gt;. It can be easy to lose sight of the fact that the amount of logic in your template lies on a spectrum, and is not a strict dichotomy.&lt;/p&gt;

&lt;h2&gt;Back to the future&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ember-composable-helpers&lt;/code&gt; doesn&amp;#39;t significantly increase the amount of logic in your templates â in fact, if used correctly, it encapsulates presentational logic within these helpers, and in many cases can help you eliminate now redundant code in your Components or Controllers.&lt;/p&gt;

&lt;p&gt;For example, you might have written something like this in your app:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { 
  Component, 
  &lt;span class=&quot;key&quot;&gt;computed&lt;/span&gt;: { filterBy, setDiff }, 
  set 
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;key&quot;&gt;activeEmployees&lt;/span&gt;: filterBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isActive&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;inactiveEmployees&lt;/span&gt;: setDiff(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;activeEmployees&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s quite common to have &amp;quot;intermediary&amp;quot; CPs in your Component that you then use in some other CP. Using &lt;code&gt;ember-composable-helpers&lt;/code&gt; lets you compose that directly in the template, where the intent becomes incredibly clear:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;h2&amp;gt;Active Employees&amp;lt;/h2&amp;gt;
{{#each (filter-by &amp;quot;isActive&amp;quot; engineers) as |employee|}}
  {{employee.name}} is active!
{{/each}}

&amp;lt;h2&amp;gt;Inactive Employees&amp;lt;/h2&amp;gt;
{{#each (reject-by &amp;quot;isActive&amp;quot; engineers) as |employee|}}
  {{employee.name}} is inactive!
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can think of a composable helper as a kind of computed property macro that you can use and compose directly in your template. And since you can compose sub-expressions in Ember, these can become powerful constructs to reduce boilerplate code in your application.&lt;/p&gt;

&lt;p&gt;With that said, remember not to get too carried away with deeply nesting helpers!&lt;/p&gt;

&lt;h2&gt;Exercise best judgment&lt;/h2&gt;

&lt;p&gt;As with all programming tools, it&amp;#39;s important to exercise best judgment and use them responsibly. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Just because you can do something doesn&amp;#39;t mean that you &lt;em&gt;should&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A well written view layer means that templates should be as declarative as possible (communicate intent clearly), and not that we should avoid logic altogether. That said, we&amp;#39;re not advocating for moving all your logic into your template â again, it&amp;#39;s not a dichotomy, but a spectrum.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;d like to see how the addon is being used, &lt;a href=&quot;https://twitter.com/katherinlaine&quot;&gt;Katherin Siracusa&lt;/a&gt; wrote an excellent &lt;a href=&quot;https://m.alphasights.com/composable-helpers-and-route-actions-two-ember-add-ons-you-should-know-655cf39fd9de#.y63wvqjpm&quot;&gt;blog post&lt;/a&gt; about how she uses &lt;code&gt;ember-composable-helpers&lt;/code&gt; at &lt;a href=&quot;https://www.alphasights.com&quot;&gt;AlphaSights&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This pattern, of performing some significant, data-changing action and subsequently performing a more ancillary, short-term state-like action, keeps arising in our application. Using [...] composable-helpers, we can take care of this in a fairly straightforward way, without much duplication and without having to worry about unintended side effects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can also join in the discussion on our Slack channel &lt;a href=&quot;https://ember-community-slackin.herokuapp.com/&quot;&gt;&lt;code&gt;#e-composable-helpers&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As always, thanks for reading!&lt;/p&gt;
</content>
  </entry><entry>
    <title>TIL: Elixir can pattern match at multiple depths in a single statement</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/13/til-elixir-can-pattern-match-at-multiple-depths-in-a-single-statement" />
    <id>https://dockyard.com/blog/2016/04/13/til-elixir-can-pattern-match-at-multiple-depths-in-a-single-statement</id>
    <category term="elixir" label="Elixir"/><category term="til" label="Til"/>
    <published>2016-04-13 00:00:00</published>
    <updated>2016-04-13 16:07:39</updated>
    <author><name>Marin Abernethy</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;One of Elixir&amp;#39;s greatest assets is its &lt;a href=&quot;https://dockyard.com/blog/2014/12/26/pattern-matching-in-elixir-for-rubyists&quot;&gt;pattern matching&lt;/a&gt;. If you have
ever used Elixir, you have probably had the pleasure of writing
something like:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def background_check(%{manager: employee} = company) do
  %{name: full_name} = employee

  from(c in Criminals,
  where: c.full_name == ^full_name,
  select: c)
  |&amp;gt; Repo.one
  |&amp;gt; case do
    nil -&amp;gt; congratulate(employee)
    criminal -&amp;gt; notify(company)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here we are assigning the entire parameter map to a variable called
&lt;code&gt;company&lt;/code&gt;, and pattern matching to get the &lt;code&gt;employee&lt;/code&gt; we want to
do a background check on. We need to query our &lt;code&gt;Criminals&lt;/code&gt; database
table for a &lt;code&gt;criminal&lt;/code&gt; with the same name as our &lt;code&gt;employee&lt;/code&gt;. To do so, we first have to grab
the &lt;code&gt;name&lt;/code&gt; property off the &lt;code&gt;employee&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Well, &lt;strong&gt;today I learned&lt;/strong&gt;, that you can have multiple matches in a
single statement! With this newly acquired knowledge, we can simplify
our &lt;code&gt;background_check()&lt;/code&gt; function definition:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def check_company(%{manager: %{name: full_name} = employee} = company) do
  from(c in Criminals,
  where: c.full_name == ^full_name,
  select: c)
  |&amp;gt; Repo.one()
  |&amp;gt; case do
    nil -&amp;gt; congratulate(employee)
    criminal -&amp;gt; notify(company)
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we can pattern match to get the &lt;code&gt;employee&lt;/code&gt;&amp;#39;s &lt;code&gt;full_name&lt;/code&gt;, while also
assigning the entire map under the &lt;code&gt;manager&lt;/code&gt; key to the variable &lt;code&gt;employee&lt;/code&gt;, as we did before.&lt;/p&gt;

&lt;p&gt;Hopefully, you learned something too! Enjoy.&lt;/p&gt;
</content>
  </entry><entry>
    <title>A Match Made In Heaven</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/10/a-match-made-in-heaven" />
    <id>https://dockyard.com/blog/2016/04/10/a-match-made-in-heaven</id>
    <category term="engineering" label="Engineering"/><category term="ember" label="Ember.js"/>
    <published>2016-04-10 00:00:00</published>
    <updated>2016-04-11 18:27:42</updated>
    <author><name>Estelle DeBlois</name></author>
    <summary>An example of how `ember-concurrency` could have helped reduce code complexity in a timer-heavy app.</summary>
    <content type="html">&lt;p&gt;Unless you&amp;#39;ve been living in a bubble, I&amp;#39;m sure you&amp;#39;ve all heard of &lt;a href=&quot;https://github.com/machty/ember-concurrency&quot;&gt;&lt;code&gt;ember-concurrency&lt;/code&gt;&lt;/a&gt;. It&amp;#39;s been all over Twitter; it&amp;#39;s been brought up on Ember Weekend; it was even mentioned during this year&amp;#39;s EmberConf keynote.&lt;/p&gt;

&lt;p&gt;This past February, &lt;a href=&quot;https://twitter.com/machty&quot;&gt;Alex Matchneer&lt;/a&gt; gave us a walkthrough of his addon at the monthly &lt;a href=&quot;http://www.meetup.com/Boston-Ember-js/events/228333385/&quot;&gt;Boston Ember.js Meetup&lt;/a&gt;. There is ample documentation and examples on the &lt;a href=&quot;http://ember-concurrency.com/&quot;&gt;website&lt;/a&gt; already, so I will forgo the details, but the TL;DR is that &lt;code&gt;ember-concurrency&lt;/code&gt; offers an elegant way to write asynchronous, cancelable tasks in an Ember app. It also leverages the power of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*&quot;&gt;generators&lt;/a&gt; so we can adopt a more readable, synchronous-like syntax.&lt;/p&gt;

&lt;p&gt;I was unfortunately way too busy working on my talk for EmberConf at the time, that I didn&amp;#39;t really get a chance to take the addon for a spin. But it was clear in my mind that the problems the addon addresses were the exact type of problems we had to solve in more traditional ways a year ago, as part of a client project.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s a project I have brought up in the past when &lt;a href=&quot;https://dockyard.com/blog/2015/03/26/bringing-ember-to-the-desktop-part&quot;&gt;demonstrating&lt;/a&gt; the use of Ember in a NW.js-powered desktop app, but it just happens to also be a perfect candidate for &lt;code&gt;ember-concurrency&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did we find ourselves having to invoke &lt;code&gt;Ember.run.cancel&lt;/code&gt; to cancel previously scheduled tasks? Yes, indeed.&lt;/li&gt;
&lt;li&gt;Did we have to clean up asynchronous tasks in &lt;code&gt;willDestroy&lt;/code&gt; hooks? Absolutely.&lt;/li&gt;
&lt;li&gt;Did we have to write guards to prevent an operation from running concurrently? For sure!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the goals of the app was to provide indoor cycling instructors with a better interface for managing and running a class, including a built-in roster and classroom map of which bikes riders had reserved, tools to start a class, start a race, view real-time stats and ranking, etc.&lt;/p&gt;

&lt;p&gt;While we wrapped up the project a while ago, I felt compelled to recreate the elements that could have benefited from &lt;code&gt;ember-concurrency&lt;/code&gt; in this (highly) simplified &lt;a href=&quot;http://brzpegasus.github.io/concurrency-demo/&quot;&gt;demo app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To give a bit of context, a class runs for a specific amount of time, e.g. 1 hour. During that time, students can ride at their own pace. At various times during the session, the instructor may initiate a race that lasts 30, 45, or 60 sec. Racing occurs numerous times during a class, and one critical piece of information the app needs to convey to the instructor is how much time is left within any given race, as well as how much time is left before the end of a class. You don&amp;#39;t want to accidentally start a 60 sec race if there&amp;#39;s only 10 sec left of class time!&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s take a look at the more traditional approach of managing a race timer with &lt;code&gt;Ember.run.later&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We have a &lt;code&gt;race-panel&lt;/code&gt; component that holds the race buttons for various race duration options. When a race button is pressed, the &lt;code&gt;race-panel&lt;/code&gt; component&amp;#39;s &lt;code&gt;startRace&lt;/code&gt; action is invoked with the duration specified by the button itself (in seconds):&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// In app/components/race-panel/component.js&lt;/span&gt;
actions: {
  startRace(duration) {
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (!get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isRaceInProgress&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)) {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.startTimer(duration);
    }
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first thing we do is check whether a race is already in progress, as there can only be at most one active at any given time.&lt;/p&gt;

&lt;p&gt;If the way is clear, we start the race timer. The main function here is &lt;code&gt;updateTimer&lt;/code&gt;, which calls itself every second, each time decrementing the race counter, until we reach 0.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;isRaceInProgress: computed.gt(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;countdown&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;),

startTimer(duration) {
  set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;countdown&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, duration);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.updateTimer();
},

updateTimer() {
  let timerId = run.later(() =&amp;gt; {
    let countdown = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.decrementProperty(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;countdown&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (countdown &amp;gt; &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;) {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.updateTimer();
    } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.stopTimer();
    }
  }, &lt;span class=&quot;integer&quot;&gt;1000&lt;/span&gt;);

  set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;timerId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, timerId);
},

stopTimer() {
  set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;timerId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;);
},
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The reason we need to store the ID of the operation started by &lt;code&gt;run.later&lt;/code&gt; is so we can cancel it should the user navigate away (e.g. by aborting the class rather than let it run to completion). This means we also need to implement a &lt;code&gt;willDestroy&lt;/code&gt; hook to do the clean up work:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;willDestroy() {
  let timerId = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;timerId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (timerId) {
    run.cancel(timerId);
  }
},
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The value assigned to the &lt;code&gt;countdown&lt;/code&gt; property is used by the component to display a race timer in the instructor&amp;#39;s UI.&lt;/p&gt;

&lt;p&gt;This isn&amp;#39;t rocket science, but if you consider the fact that we also need to disable race buttons depending on whether a race is already in progress, or disable specific race duration options depending on how much time is left in a class, all while keeping track of the class overall progress and possible early termination, this does end up being quite a lot of timer-related code to get right and maintain.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;ember-concurrency&lt;/code&gt;, the above can be simplified to just the following:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;raceTask: task(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;* (duration) {
  let countdown = set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;countdown&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, duration);
  &lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; (countdown &amp;gt; &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;) {
    yield timeout(&lt;span class=&quot;integer&quot;&gt;1000&lt;/span&gt;);
    countdown = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.decrementProperty(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;countdown&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }
}).drop()
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The generator function allows us to write asynchronous code that feels synchronous, while the special &lt;code&gt;task&lt;/code&gt; function lets us adhere to the idea of &lt;a href=&quot;http://alexmatchneer.com/ec-prezo/#/?slide=structured-concurrency-1&quot;&gt;structured concurrency&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can instantiate the race task directly from the template, using the &lt;code&gt;{{perform}}&lt;/code&gt; helper that the addon provides. In addition, figuring out if a race is in progress is just a matter of checking the value of &lt;code&gt;raceTask.isRunning&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#each raceDurations as |duration|}}
  &amp;lt;button disabled={{or raceTask.isRunning (gte duration classTimeRemaining)}}
      onclick={{perform raceTask duration}}&amp;gt;{{duration}}&amp;lt;/button&amp;gt;
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Even though we are disabling the race buttons when a race is already in progress, having the option to use the &lt;code&gt;.drop()&lt;/code&gt; task modifier in the component code guards us further against concurrent races in a more elegant way than if we had to do so via an internal property. The modifier ensures that future requests to run the race task will be dropped until the current one completes.&lt;/p&gt;

&lt;p&gt;The best part, however, is that we no longer need those &lt;code&gt;willDestroy&lt;/code&gt; hooks as &lt;code&gt;ember-concurrency&lt;/code&gt; automatically manages the lifecycle of these tasks for us, so we can rest at ease knowing that when our component is destroyed, all tasks will be cancelled and cleaned up as well.&lt;/p&gt;

&lt;p&gt;The result is a clear reduction in boilerplate code to manage asynchronous tasks and timers, as well as code that is much more readable overall. In short, I wish this had existed a year ago when we were still active on the project, but these sorts of asynchronous operations are common enough that they&amp;#39;re sure to come up again. They don&amp;#39;t have to necessarily deal with time-related events, as you can &lt;code&gt;yield&lt;/code&gt; promises that hit some backend API as well, and let &lt;code&gt;ember-concurrency&lt;/code&gt; handle the trickier concurrency or task cancellation logic.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Some user involvement is good for design. But is more better?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/05/some-user-involvement-is-good-for-design-but-is-more-better" />
    <id>https://dockyard.com/blog/2016/04/05/some-user-involvement-is-good-for-design-but-is-more-better</id>
    <category term="design-process" label="Design Process"/><category term="design" label="Design"/><category term="design-thinking" label="Design Thinking"/>
    <published>2016-04-05 00:00:00</published>
    <updated>2016-04-06 15:08:40</updated>
    <author><name>Mark Kaplan</name></author>
    <summary>Collaborative design is being touted as the next level of user-centered design. But it doesn&#39;t guarantee a better outcome. Learn about some of the pitfalls â and how to avoid them.</summary>
    <content type="html">&lt;p&gt;In a typical UX project, user involvement begins early on, as part of research. This leads to insights, which lead to a concise definition of the design problem(s) we&amp;#39;re tasked with solving. Then we disappear and transmogrify our inputs into concepts. The users return for usability testing. Their collective feedback informs the next iteration of the concept.&lt;/p&gt;

&lt;p&gt;A movement to keep users around for the entire design process has been gaining traction. Whether it&amp;#39;s called &amp;quot;collaborative design,&amp;quot; or &amp;quot;co-creation,&amp;quot; or &amp;quot;generative design,&amp;quot; the starting premise is that everyone, users included, is capable of being a designer. Stick figures welcome.&lt;/p&gt;

&lt;p&gt;I recently attended a local design thinking meetup which sought to introduce us to co-creation by having us each design a new service for ordering pizza or sushi. First weâd each sketch something using Sharpies and Post-Its. Then weâd engage one our peers as a âuserâ to interpret and edit what they saw. We repeated this 3 times, with each user moving the design forward from the point where the last left off.&lt;/p&gt;

&lt;p&gt;It was a lot of fun and highly engaging. The reactions from the participants were overwhelmingly enthusiastic. But I was surprised to find that the end result was a room full of nearly identical designs â both to each other and to what already exists in the marketplace. All were some variation of: 1 Select a location, 2 View the menu, 3 Order something, 4 Check out, 5 Thank you.&lt;/p&gt;

&lt;p&gt;With a design brief that was akin to, &amp;quot;Design a new car â anything you want,&amp;quot; we ended up with a lot full of lookalike beige sedans. No bold hypercars. No original go-anywhere vehicles that could hop a chasm if commanded to do so. This outcome was especially concerning given we weren&amp;#39;t &amp;quot;typical users&amp;quot; â we were mostly &amp;quot;designers.&amp;quot; So, what happened?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/pzsFUsU.jpg&quot; alt=&quot;beigecar&quot;&gt;&lt;/p&gt;

&lt;p&gt;Image Credit: &lt;a href=&quot;http://www.kiamedia.com/us/en/models/amanti/2006&quot;&gt;KIA Media&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Donât Facilitate â Collaborate&lt;/h2&gt;

&lt;p&gt;We were asked to adopt a facilitator&amp;#39;s mindset when co-designing. This meant that we pushed and prodded our users into both finding problems and fixing them with design.&lt;/p&gt;

&lt;p&gt;Users are experts in identifying that problems exist. This is why usability testing works so well. But their ability to articulate the cause(s) of problems and designing solutions varies with their expertise, experience, and aptitudes. A user can tell you they hear a rattle when making a left turn, but unless they have experience in auto mechanics, they likely canât tell you whatâs causing the noise, or make the repair.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/DiADxmL.jpg&quot; alt=&quot;mechanic&quot;&gt;&lt;/p&gt;

&lt;p&gt;Image Credit: &lt;a href=&quot;http://funzypics.com/board/pins/376/16036&quot;&gt;Funzy Pics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finding problems and fixing problems are not the same activity. While simple problems have an obvious cause and effect, most problems faced by designers are complicated or complex â their causes and/or solutions are not obvious and require further analysis or expertise. Homer Simpson can bang together a doghouse from a bunch of boards, but only skilled architects, engineers and builders can erect a skyscraper and expect it to stand.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/0H4NRPL.jpg&quot; alt=&quot;homerdoghouse&quot;&gt;&lt;/p&gt;

&lt;p&gt;Image Credit: &lt;a href=&quot;https://frinkiac.com/caption/S03E16/1107454&quot;&gt;frinkiac.com&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Tips for Designers:&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Design with the user as an equal partner. Think through problems and solutions together, allowing both of your perspectives and expertise (them as user, you as designer) to inform where things go.&lt;/li&gt;
&lt;li&gt;Put faith in what users identify as problems. Even if all they can articulate is that âsomething doesnât feel right,â chances are, theyâve stumbled upon something that needs to be thought through.&lt;/li&gt;
&lt;li&gt;Encourage multiple cause hypotheses and multiple solutions by coaching the user through the problem solving process:  What do you think is the cause of that problem?  What else could it be?  What else? Whatâs a solution for it?  Whatâs another?  And another?&lt;/li&gt;
&lt;li&gt;Pool the ideas generated from co-creation activities with other possible ideas conceived separately by designers; downselect from there. Designers have an obligation to propose the best possible solutions. It is important to include ideas from designers who know many design patterns (and when to use them), understand context and behavior, and give equal weight to what&amp;#39;s left unsaid or undone.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Use the Appropriate Concept Fidelity&lt;/h2&gt;

&lt;p&gt;The ground rules for the collaborative part of the pizza/sushi activity were to use Socratic questioning, similar to how we do it in usability testing: the facilitator should answer âWhat is this?â with &amp;quot;What do you think it is?&amp;quot;  As a result, none of my users were able to decipher this image:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/WpoacJi.jpg&quot; alt=&quot;stickynote&quot;&gt;&lt;/p&gt;

&lt;p&gt;It was supposed to be a livestream of a sushi chef making your sushi, in an attempt to bring the sushi-bar experience home.&lt;/p&gt;

&lt;p&gt;Because the method we used called for real-time editing, one of the potential differentiating features was edited-out solely because of a poorly drawn stick figure. So much for the premise that &amp;quot;everyone is a designer.&amp;quot;&lt;/p&gt;

&lt;h3&gt;Tips for Designers:&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;When sketching concepts, consider increasing the fidelity beyond the bare minimum of Sharpies on Post-its â for example, use pencils and/or larger Post-Its. This can allow for a bit more detail and/or annotations for those that prefer words to pictures.&lt;/li&gt;
&lt;li&gt;If a user cannot interpret a low-fidelity sketch, allow clarifying questions to be asked and answered, in addition to Socratic questioning.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Avoid Design by Committee&lt;/h2&gt;

&lt;p&gt;Teamwork is effective in accomplishing shared goals: Dribble, pass, shoot, score. But have you heard the expression &amp;quot;too many cooks spoil the broth?&amp;quot;  The idea is that each might add a different ingredient, which, in the end, creates something unpalatable.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/Qw31rmg.jpg&quot; alt=&quot;designcurve&quot;&gt;&lt;/p&gt;

&lt;p&gt;Image Credit: &lt;a href=&quot;https://moz.com/blog/how-to-ruin-a-web-design-the-design-curve&quot;&gt;Moz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we allow every user to manipulate the design â one after the other â we may end up with an unappetizing design that pleases no one. Thatâs what happened In our sushi/pizza exercise â each user started where the previous user left off and were free to change the design to their liking.&lt;/p&gt;

&lt;p&gt;What if a user changed or removed something a subsequent user might have found compelling in its earlier form?  What if the final user added something that none of the previous users would have found to their liking, or removed something that excited all the others?  Clearly, the order in which users took their turn designing impacted the outcome. It was a handoff, rather than a handshake.&lt;/p&gt;

&lt;p&gt;You don&amp;#39;t need a whole committee to spoil the broth â one empowered user can muck things up quite well on their own given half a chance. Homer Simpson was tasked with designing a car for the &amp;quot;average American&amp;quot; and came up with The Homer, a completely unworkable solution:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/vbeJYbg.png&quot; alt=&quot;thehomer&quot;&gt;&lt;/p&gt;

&lt;p&gt;Image Credit: &lt;a href=&quot;http://simpsons.wikia.com/wiki/The_Homer&quot;&gt;Simpsons Wiki&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Tips for Designers:&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Provide users with a common problem statement. All designers need context and constraints. Provide these in a well-articulated problem statement (e.g. &amp;quot;We&amp;#39;re trying to do [something] for [someone], without [negative consequences/constraints]&amp;quot;). Edit out any ideas that don&amp;#39;t conform to the statement.&lt;/li&gt;
&lt;li&gt;Reset the concept between users. Let everyone begin at the same place and end up where they will. Compare and contrast the results.&lt;/li&gt;
&lt;li&gt;Use other collaborative design methods that allow multiple users to work together on the same problem at the same time. Two examples are &lt;a href=&quot;http://www.lego.com/en-us/seriousplay&quot;&gt;Lego Serious Play&lt;/a&gt;, and &lt;a href=&quot;http://www.bispublishers.com/elizabeth-sanders-and-pieter-jan-stappers-convivia.html&quot;&gt;Convivial Toolbox&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As seen with the pizza and sushi app exercise, collaborative design has the potential lead to a lesser result than if users had only been consulted before and after the act of designing. But it still offers tremendous potential to improve products and services. In the next post, Iâll talk about some areas where collaborative design can add value.&lt;/p&gt;
</content>
  </entry><entry>
    <title>EmberConf 2016 - Bigger and Better</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/04/01/emberconf-2016-bigger-better" />
    <id>https://dockyard.com/blog/2016/04/01/emberconf-2016-bigger-better</id>
    <category term="engineering" label="Engineering"/><category term="ember" label="Ember.js"/><category term="opinion" label="Opinion"/>
    <published>2016-04-01 00:00:00</published>
    <updated>2016-04-01 20:17:00</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A personal look at EmberConf 2016</summary>
    <content type="html">&lt;p&gt;Leading up to this year&amp;#39;s &lt;a href=&quot;http://emberconf.com&quot;&gt;EmberConf&lt;/a&gt; I wasn&amp;#39;t sure I was going to attend.
My indecisiveness had nothing to do with concerns about Ember or DockYard&amp;#39;s
commitment to the framework. It was simply that I personally haven&amp;#39;t been
writing much Ember over the past six months. Between being a new dad, buying
a house, running DockYard, and exploring Elixir I lacked the bandwidth to
keep up with what has been happening in Ember.&lt;/p&gt;

&lt;p&gt;The deciding factor was to lend moral support for two of our
engineers who were speaking: &lt;a href=&quot;http://twitter.com/edeblois&quot;&gt;Estelle DeBlois&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/sugarpirate_&quot;&gt;Lauren Tan&lt;/a&gt;. They both
gave great talks and if that was the only reason it would have been more
than worth the trip. However, like many things, I was thankfully wrong
about my concerns attending and would like to share my experience this
year.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://images3.cloudhdr.com/users/63df8506-b9d4-11e2-944b-eebc857a8e43/thumbnails/c961d5f8-f614-11e5-912c-ca74e7c7373d/hd_P3293226.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;.&lt;a href=&quot;https://twitter.com/sugarpirate_&quot;&gt;@sugarpirate_&lt;/a&gt;
takes the stage at &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt; //
&lt;a href=&quot;https://twitter.com/hashtag/emberjs?src=hash&quot;&gt;#emberjs&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/DockYard&quot;&gt;@DockYard&lt;/a&gt; &lt;a
href=&quot;https://t.co/aWMmgIaIMp&quot;&gt;pic.twitter.com/aWMmgIaIMp&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Mike North (@michaellnorth) &lt;a
href=&quot;https://twitter.com/michaellnorth/status/715245083927314432&quot;&gt;March
30, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;First, I&amp;#39;d like to point out how great of a job &lt;a href=&quot;http://twitter.com/wifelette&quot;&gt;Leah Silber&lt;/a&gt; has done
building and organizing EmberConf. This year the attendance was just shy
of 1,000. That&amp;#39;s almost double from last year. I&amp;#39;ve heard the aim is for
1,500 next year. As someone who has run a few conferences I can say that
Leah has been kicking ass.&lt;/p&gt;

&lt;p&gt;My time was split about 50/50 between the hallway track and the talks. &lt;a href=&quot;https://twitter.com/tomdale&quot;&gt;Tom&lt;/a&gt; &amp;amp;
&lt;a href=&quot;https://twitter.com/wycats&quot;&gt;Yehuda&amp;#39;s&lt;/a&gt; keynote was probably my favorite talk as we&amp;#39;re very interested
in the mobile web becoming more competitive against native. Elements
of that keynote should play out over the next year or so to help
position Ember as the best choice for &lt;a href=&quot;https://developers.google.com/web/progressive-web-apps?hl=en&quot;&gt;Progressive Web
Applications&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Enjoying &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt; so
far w &lt;a href=&quot;https://twitter.com/bcardarella&quot;&gt;@bcardarella&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/jeremy_w_rowe&quot;&gt;@jeremy_w_rowe&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/tundal45&quot;&gt;@tundal45&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/atonse&quot;&gt;@atonse&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/sweatypitts&quot;&gt;@sweatypitts&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/hashtag/emberjs?src=hash&quot;&gt;#emberjs&lt;/a&gt; &lt;a
href=&quot;https://t.co/J7Tr8fWTex&quot;&gt;pic.twitter.com/J7Tr8fWTex&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Tracy Lee | ladyleet (@ladyleet) &lt;a
href=&quot;https://twitter.com/ladyleet/status/714869714799894528&quot;&gt;March 29,
2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;I was really impressed with how many people were interested in
&lt;a href=&quot;http://elixir-lang.org&quot;&gt;Elixir&lt;/a&gt;.
Easily a majority of the conversations I had were with people 
curious about Elixir or actively using it. I don&amp;#39;t want to dwell on
Elixir too much because this was EmberConf but this reinforced my
opinion that Elixir/Phoenix are a natural fit for Ember backends. It
seems there are many people out there that have the same idea.&lt;/p&gt;

&lt;p&gt;This is now my fourth EmberConf (if I&amp;#39;m counting the original
&lt;a href=&quot;https://web.archive.org/web/20130613165616/http://lanyrd.com/2013/ember-camp&quot;&gt;EmberCamp&lt;/a&gt;) and catching up with old friends is important but I really
enjoyed meeting new people. As always, the regret is not meeting enough
people. I wish that future EmberConfs were more days with more down time. I
realize this is not realistic as the days really increase the cost to 
run the conference and
more down time creates less incentive for companies to send employees,
but I personally find the most value from networking.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Climbing right after &lt;a
href=&quot;https://twitter.com/EmberConf&quot;&gt;@EmberConf&lt;/a&gt; with these great
emberiÃ±os ïªï &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt; &lt;a
href=&quot;https://t.co/TsWWZ1c2mF&quot;&gt;pic.twitter.com/TsWWZ1c2mF&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Filipe BraganÃ§a (@filipecrosk) &lt;a
href=&quot;https://twitter.com/filipecrosk/status/715409635033817088&quot;&gt;March
31, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;I am aware of DockYard&amp;#39;s place in the Ember community. Thinking
back to the earlier &lt;a href=&quot;http://railsconf.com&quot;&gt;RailsConfs&lt;/a&gt;, and companies that were in a similiar
position to DockYard, I don&amp;#39;t recall the leaders of those companies being
very accessible. There were clear social cliques that these people
stuck to. I&amp;#39;m trying not to repeat that. At times I found
myself gravitating towards friends but after a few minutes I&amp;#39;d excuse
myself so I could meet new people.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Thanks &lt;a href=&quot;https://twitter.com/DockYard&quot;&gt;@DockYard&lt;/a&gt;
for sponsoring amazing time at &lt;a
href=&quot;https://twitter.com/GroundKontrol&quot;&gt;@GroundKontrol&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt; &lt;a
href=&quot;https://t.co/2NEiXp4ZbO&quot;&gt;pic.twitter.com/2NEiXp4ZbO&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Tom Chen (@tchen) &lt;a
href=&quot;https://twitter.com/tchen/status/715042486171910144&quot;&gt;March 30,
2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;Tuesday night we hosted an event at &lt;a href=&quot;http://groundkontrol.com/&quot;&gt;Ground Kontrol&lt;/a&gt;. For those
unfamiliar, Ground Kontrol is a video arcade with a bar. We rented the
entire space for three hours and had close to 100 EmberConf attendees
through the doors that evening. All the games were free. When I walked
in to get the place ready for the event it was like stepping into a time
machine. Nearly ever coin-op game from my childhood was there. If I
learned anything that evening it is that I vastly over estimated my
skills as kid. Or I am just rusty. Or it was the controller... all of
the controllers. Also, I am really out of touch with modern arcade games
as I was completely unaware of this &lt;a href=&quot;http://killerqueenarcade.com/&quot;&gt;Killer Queen&lt;/a&gt; game.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Killer Queen at Ground Control at 9! Ping us and let us know
if you can make it!&lt;a
href=&quot;https://twitter.com/hashtag/EmberConf?src=hash&quot;&gt;#EmberConf&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Ember Weekend (@emberweekend) &lt;a
href=&quot;https://twitter.com/emberweekend/status/715347575491002369&quot;&gt;March
31, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;A good conference leaves you feeling energized and wanting more,
EmberConf has done that for me every year. A great conference gives you
the opportunity to connect with friends new and old, and it takes a
great community to build what Ember has. We hear a lot about &lt;em&gt;Ember vs X&lt;/em&gt;.
Not often enough do I hear the practitioners of other frameworks
bragging about their community the way Ember does. I think there is a
good reason for that. Twenty years from now I&amp;#39;m not going to give a shit
about which library rendered which obscure demo the fastest. But I will
remember...&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Who is a better puppy? &lt;a
href=&quot;https://twitter.com/bcardarella&quot;&gt;@bcardarella&lt;/a&gt; or &lt;a
href=&quot;https://twitter.com/mikepack_&quot;&gt;@mikepack_&lt;/a&gt; ? Follow
&amp;quot;modernweb&amp;quot; on snapchat for the full story &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt; &lt;a
href=&quot;https://t.co/VBPruOLft2&quot;&gt;pic.twitter.com/VBPruOLft2&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Tracy Lee | ladyleet (@ladyleet) &lt;a
href=&quot;https://twitter.com/ladyleet/status/714298487857262592&quot;&gt;March 28,
2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Having some fun with the tomster at &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/EmberConf&quot;&gt;@EmberConf&lt;/a&gt; ï¨ï´ &lt;a
href=&quot;https://t.co/zjFd3ll5EB&quot;&gt;pic.twitter.com/zjFd3ll5EB&lt;/a&gt;&lt;/p&gt;&amp;mdash;
JuliÃ¡n CÃ¡rdenas Mazo (@juliankmazo) &lt;a
href=&quot;https://twitter.com/juliankmazo/status/715343497956438016&quot;&gt;March
31, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Kudos to &lt;a
href=&quot;https://twitter.com/thejameskyle&quot;&gt;@thejameskyle&lt;/a&gt; for the most
visually entertaining talk at &lt;a
href=&quot;https://twitter.com/hashtag/EmberConf?src=hash&quot;&gt;#EmberConf&lt;/a&gt; &lt;a
href=&quot;https://t.co/INwmqboMVo&quot;&gt;pic.twitter.com/INwmqboMVo&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Wedge Salad Antilles (@suzidao) &lt;a
href=&quot;https://twitter.com/suzidao/status/715297031703568384&quot;&gt;March 30,
2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;I love &lt;a href=&quot;https://twitter.com/EmberConf&quot;&gt;@emberconf&lt;/a&gt;
&lt;a href=&quot;https://twitter.com/hashtag/ImgPlay?src=hash&quot;&gt;#ImgPlay&lt;/a&gt; &lt;a
href=&quot;https://t.co/plZWIsoyku&quot;&gt;pic.twitter.com/plZWIsoyku&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Emanuele Tozzato (@mekdigital) &lt;a
href=&quot;https://twitter.com/mekdigital/status/714954113050501122&quot;&gt;March
29, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Loved my new Ember socks :) thanks &lt;a
href=&quot;https://twitter.com/EmberConf&quot;&gt;@EmberConf&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/hashtag/portland?src=hash&quot;&gt;#portland&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/hashtag/socks?src=hash&quot;&gt;#socks&lt;/a&gt; &lt;a
href=&quot;https://t.co/X2odXYlgVK&quot;&gt;pic.twitter.com/X2odXYlgVK&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Filipe BraganÃ§a (@filipecrosk) &lt;a
href=&quot;https://twitter.com/filipecrosk/status/714592198868611072&quot;&gt;March
28, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;So good seeing &lt;a
href=&quot;https://twitter.com/cball_&quot;&gt;@cball_&lt;/a&gt; at &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt;!
â¤ï¸ïïïï see you at &lt;a
href=&quot;https://twitter.com/WickedGoodEmber&quot;&gt;@wickedgoodember&lt;/a&gt;? &lt;a
href=&quot;https://twitter.com/hashtag/emberjs?src=hash&quot;&gt;#emberjs&lt;/a&gt; &lt;a
href=&quot;https://t.co/fpW6HlinlA&quot;&gt;pic.twitter.com/fpW6HlinlA&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Tracy Lee | ladyleet (@ladyleet) &lt;a
href=&quot;https://twitter.com/ladyleet/status/715719754661502977&quot;&gt;April 1,
2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot;
dir=&quot;ltr&quot;&gt;Farewell Ember Conf, until next time. &lt;a
href=&quot;https://twitter.com/hashtag/emberconf?src=hash&quot;&gt;#emberconf&lt;/a&gt; &lt;a
href=&quot;https://t.co/7PsVcd7lsR&quot;&gt;pic.twitter.com/7PsVcd7lsR&lt;/a&gt;&lt;/p&gt;&amp;mdash;
tomguisuru (@tomoguisuru) &lt;a
href=&quot;https://twitter.com/tomoguisuru/status/715415989110747136&quot;&gt;March
31, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;...the people.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Announcing VerifyOrigin</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/31/announcing-verify-origin" />
    <id>https://dockyard.com/blog/2016/03/31/announcing-verify-origin</id>
    <category term="phoenix" label="Phoenix"/><category term="security" label="Security"/>
    <published>2016-03-31 00:00:00</published>
    <updated>2016-03-31 14:49:36</updated>
    <author><name>Dan McClain</name></author>
    <summary>Securing your API without a CSRF token</summary>
    <content type="html">&lt;p&gt;In web applications, if you are using cookies for storing authentication
state, you should be worrying about &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-site_request_forgery&quot;&gt;Cross Site Request Forgery&lt;/a&gt;
(CSRF). In short, when using cookies, other sites can create an HTML
form that submits to your backend. When your browser submits that form,
it will attach any cookies it has that are associated with the URL that
the form is submitted to. Without any steps taken to mitigate this, a
malicious third party could create a form on their site that performs an
action on application, maybe as harmless as following them on a site, or
as malicious as deleting your account or transferring funds. &lt;a href=&quot;https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)&quot;&gt;OWASP has
more details on CSRF attacks as well&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Typical CSRF prevention&lt;/h2&gt;

&lt;p&gt;The way that most applications mitigate CSRF attacks is by utilizing a
synchronizer CSRF token that is stored in a hidden HTML input in the
form which matches a token in the current user&amp;#39;s session. In short,
malicious forms will be lacking this token and will be rejected. &lt;a href=&quot;https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet#General_Recommendation:_Synchronizer_Token_Pattern&quot;&gt;More
details on token based mitigation are covered in this
OWASP page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;What about Single Page applications? Is a JSON only API vulnerable?&lt;/h2&gt;

&lt;p&gt;CSRF tokens work well for server side rendered applications (SSR), since
the HTML generated on the server can securely include the token that is in the
session cookie. But what about single page application like Ember? Can
you craft an HTML form to submit a valid request to a JSON based API?
The answer is &lt;a href=&quot;https://www.gracefulsecurity.com/csrf-vs-json/&quot;&gt;yes it is possible&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ok, so how can we secure this API backend without a CSRF token?&lt;/p&gt;

&lt;h3&gt;Enter Referer/Origin header verification&lt;/h3&gt;

&lt;p&gt;With the exception of &lt;code&gt;GET&lt;/code&gt; requests, when your browser submits a
request, it attaches both a &lt;code&gt;Referer&lt;/code&gt; (that typo is historical) and
&lt;code&gt;Origin&lt;/code&gt; header. The &lt;code&gt;Origin&lt;/code&gt; header is a bit newer, it was originally
introduced for Cross Origin Resource Sharing (CORS), but has been
repurposed for CSRF mitigation as well. We can use the &lt;code&gt;Referer&lt;/code&gt; or
&lt;code&gt;Origin&lt;/code&gt; header to verify that the request originated from the domain we
expect. In this case, I prefer the &lt;code&gt;Origin&lt;/code&gt; header. When a request
originates at an HTTPS page and is made against an HTTP page, the
&lt;code&gt;Referer&lt;/code&gt; header is dropped, while the &lt;code&gt;Origin&lt;/code&gt; header will continue to
be sent. Both &lt;a href=&quot;https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet#CSRF_Prevention_without_a_Synchronizer_Token&quot;&gt;OWASP&lt;/a&gt; and &lt;a href=&quot;https://wiki.mozilla.org/Security/Origin&quot;&gt;Mozilla&lt;/a&gt; talk
about the validity of using the &lt;code&gt;Origin&lt;/code&gt; header as a way to mitigate
CSRF attacks.&lt;/p&gt;

&lt;h2&gt;Places where CSRF prevention fails&lt;/h2&gt;

&lt;p&gt;No matter how good your CSRF prevention is, there are other vectors that
will open your application to malicious requests. If your session cookie
is not &lt;code&gt;HTTPOnly&lt;/code&gt; (&lt;a href=&quot;https://www.owasp.org/index.php/HTTPOnly&quot;&gt;details&lt;/a&gt;), and/or you accidentally allow malicious JavaScript to
execute on your site, you have a couple of problems. When not using
&lt;code&gt;HTTPOnly&lt;/code&gt; cookies, your cookies can be retrieved via JavaScript, and if
you have malicious JavaScript on your site, someone could siphon off all
your session cookies. At that point, this third party could forge any
header it needs to, and then include the session cookie to automate requests
against your server, so it could bypass the &lt;code&gt;Origin&lt;/code&gt; check. They could
also replace the cookie in their browser with another person&amp;#39;s cookie
that they stole, and use your site as that user, bypassing CSRF Tokens.
If your cookie is marked as &lt;code&gt;HTTPOnly&lt;/code&gt;, they can still use malicious
JavaScript via a &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-site_scripting&quot;&gt;Cross Site Scripting&lt;/a&gt; (XSS) attack, since any users&amp;#39;
browser that executes this malicious JavaScript will make the request
with either the necessary CSRF token or &lt;code&gt;Origin&lt;/code&gt; header.&lt;/p&gt;

&lt;h2&gt;Ok, so why all this information about CSRF mitigation?&lt;/h2&gt;

&lt;p&gt;At DockYard, we produce Ember applications for our clients. Since Ember
is a single page application, &lt;code&gt;Origin&lt;/code&gt; header checking is the best way
we can protect any backends we produce. To the end, I recently published
&lt;a href=&quot;https://github.com/danmcclain/verify_origin&quot;&gt;VerifyOrigin&lt;/a&gt; to
&lt;a href=&quot;https://hex.pm/packages/verify_origin&quot;&gt;hex.pm&lt;/a&gt;. VerifyOrigin
provides a &lt;code&gt;Plug&lt;/code&gt; you can add to your applications pipeline to only
allow requests from &lt;code&gt;Origin&lt;/code&gt;s you expect:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;plug VerifyOrigin, [&amp;quot;https://example.com&amp;quot;]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The plug expects a list of valid &lt;code&gt;Origin&lt;/code&gt; URLs. If the request does not
have an &lt;code&gt;Origin&lt;/code&gt; header that matches your list, then it returns a &lt;code&gt;400
Bad Request&lt;/code&gt; response to the client. Simple CSRF mitigation for your
Phoenix app is at your fingertips!&lt;/p&gt;

&lt;p&gt;A special thanks to &lt;a href=&quot;https://twitter.com/cji&quot;&gt;Craig Ingram&lt;/a&gt;, who I consulted with multiple
times when coming up with this plug!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Announcing: ember-deferred-content</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/30/announcing-ember-deferred-content" />
    <id>https://dockyard.com/blog/2016/03/30/announcing-ember-deferred-content</id>
    <category term="ember" label="Ember.js"/>
    <published>2016-03-30 00:00:00</published>
    <updated>2016-04-01 17:10:06</updated>
    <author><name>Dan McClain</name></author>
    <summary>Handling the states of async content</summary>
    <content type="html">&lt;p&gt;There are times that you may have some content that you want to load
outside of the &lt;code&gt;model&lt;/code&gt; hook. An example of this would be a blog post with
comments. You want your post to be loaded in the &lt;code&gt;model&lt;/code&gt; hook of your
route, but don&amp;#39;t necessarily want to wait for all of the comments to
load before displaying the blog post.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/danmcclain/ember-deferred-content&quot;&gt;ember-deferred-content&lt;/a&gt; takes the promise you need to resolve to show
your content, and yields four subcomponents that you can use to show
content during the different states of your promise:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#deferred-content promise=promise as |d|}}
  {{#d.settled}}&amp;lt;h2&amp;gt;Your content!&amp;lt;/h2&amp;gt;{{/d.settled}}
  {{#d.pending}}Loading your content...{{/d.pending}}
  {{#d.rejected as |reason|}}&amp;lt;strong&amp;gt;Could not load your content:&amp;lt;/strong&amp;gt; {{reason}}{{/d.rejected}}
  {{#d.fulfilled as |stuff|}}&amp;lt;strong&amp;gt;Loaded:&amp;lt;/strong&amp;gt; {{stuff}}{{/d.fulfilled}}
{{/deferred-content}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you want to handle transitions with something like &lt;a href=&quot;http://ember-animation.github.io/liquid-fire/&quot;&gt;liquid
fire&lt;/a&gt;, you can use &lt;code&gt;if&lt;/code&gt; (or &lt;code&gt;liquid-if&lt;/code&gt;) statements and the flags provided:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt; {{#deferred-content promise=post.comments as |d|}}
    {{#if d.isSettled}} &amp;lt;h2&amp;gt;Comments&amp;lt;/h2&amp;gt; {{/if}}
    {{#if d.isPending}} &amp;lt;img src=&amp;quot;spinner.gif&amp;quot;&amp;gt; {{/if}}
    {{#if d.isFulfilled}}
      &amp;lt;ul&amp;gt;
        {{#each d.content as |comment|}}
          &amp;lt;li&amp;gt;{{comment.author}} said: {{comment.body}}
        {{/each}}
      &amp;lt;/ul&amp;gt;
    {{/if}}
    {{#if d.isRejected}} Could not load comments: {{d.content}} {{/if}}
  {{/deferred-content}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://ember-twiddle.com/8ca7a5edd5ab0df72c0c?numColumns=1&amp;amp;openFiles=application.template.hbs%2C&quot;&gt;Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see above, you pass the promise to the &lt;code&gt;deferred-content&lt;/code&gt; component,
then you get four contextual components for the four states of the promise:
&lt;code&gt;settled&lt;/code&gt;, &lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;fulfilled&lt;/code&gt;, and &lt;code&gt;rejected&lt;/code&gt;. Each is a block component where the
content you place the content you want to see when the promise is in that
state. &lt;code&gt;rejected&lt;/code&gt; and &lt;code&gt;fulfilled&lt;/code&gt; yield the result of their states to the
component so you can reference the result of the promise.&lt;/p&gt;

&lt;h2&gt;Let&amp;#39;s take one step further&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s peak at an example in which we have no asynchrony in our &lt;code&gt;model&lt;/code&gt;
hook: &lt;a href=&quot;http://deferred-example.danmcclain.net/&quot;&gt;Example app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So what&amp;#39;s happening here? This app simulates a slow loading blog post.
We have some basic information on the blog list page (the title), and we
can use this to do a hero animation right away, instead of waiting for
the &lt;code&gt;model&lt;/code&gt; hook to resolve. Clicking the deferred link shows that, as
clicking on the normal link waits for the model to be fetched in the
&lt;code&gt;model&lt;/code&gt; hook before starting the transition.&lt;/p&gt;

&lt;h3&gt;Deferring asynchrony to the template&lt;/h3&gt;

&lt;p&gt;When we use &lt;code&gt;deferred-content&lt;/code&gt; to show the loading state note that the
URL update and animation happens immediately, as opposed to waiting for
the &lt;code&gt;model&lt;/code&gt; hook to resolve. This approach will also encourage you to
model your data slightly differently so that you push your asynchronous
to logical divisions in your templates.&lt;/p&gt;

&lt;p&gt;By utilizing animations to mask your loading times you improve your &lt;a href=&quot;http://blog.teamtreehouse.com/perceived-performance&quot;&gt;perceived
performance&lt;/a&gt;. Given that two sites take the same ammount of time to
render, the one with a loading animation will be perceived as
faster, and tends to be less likely to lose conversions.&lt;/p&gt;

&lt;h3&gt;Where this really shines&lt;/h3&gt;

&lt;p&gt;Pages with multiple pieces of async content benefit the most from this
approach. You can load in each piece of content as you receive it,
making the page more responsive.&lt;/p&gt;

&lt;h2&gt;Handle the states of your content easily&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;ember-deferred-content&lt;/code&gt; it becomes trivial to handle async content after
rendering the page. You can provide a pending state to let your users know that
content is incoming, and switch over to the actual content once it&amp;#39;s loaded.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Served with FastBoot (again)</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/29/served-with-fastboot-again" />
    <id>https://dockyard.com/blog/2016/03/29/served-with-fastboot-again</id>
    <category term="ember" label="Ember.js"/><category term="fastboot" label="Fastboot"/>
    <published>2016-03-29 00:00:00</published>
    <updated>2016-03-29 15:36:24</updated>
    <author><name>Dan McClain</name></author>
    <summary>You are now reading a live FastBoot site</summary>
    <content type="html">&lt;p&gt;A little less than a year ago, we launched the redesigned DockYard.com,
which at launch was running an early version of &lt;a href=&quot;https://github.com/tildeio/ember-cli-fastboot&quot;&gt;FastBoot&lt;/a&gt;.
And by early version, I mean alpha version, when Ember had some memory
leaks, which caused FastBoot to crash. Since then, DockYard.com was a
&lt;em&gt;FastBoot Rendered, Statically Served&lt;/em&gt;â¢ site. I would run a local
instance of FastBoot, use a custom crawler to crawl everything but the
blog and save static files of the site. I would then push those static
files to the server and let Nginx serve the files. This gained us the
benefits of running FastBoot (except on the blog), without FastBoot
running and crashing because of the memory leaks. The reason that the
blog was left out was because of the fact that using &lt;code&gt;{{{blog.body}}}&lt;/code&gt;
was not rendered in that version of FastBoot, leaving the post content
of every blog post out of the page source.&lt;/p&gt;

&lt;h2&gt;FastBoot keeps moving&lt;/h2&gt;

&lt;p&gt;As time went on, the memory leaks in Ember were fixed, and FastBoot has
been continually developed. Ember has also been updated so that stable
releases, as of 2.3.0, support FastBoot. Previously you had to use the
canary version and enable a feature flag to allow Ember to work with
Fastboot.&lt;/p&gt;

&lt;p&gt;And recently, I revisited the DockYard site and worked to reimplement
FastBoot. In terms of work on DockYard.com, there was little to no work,
we had previously submitted pull requests to addons we were using to
make them FastBoot compatible. Most of the recent work was around
contributing to FastBoot to help make it easier for applications to drop
in.&lt;/p&gt;

&lt;p&gt;There have been many contributors to FastBoot, helping to make it a
reality.  Ember Data, &lt;a href=&quot;http://emberjs.com/blog/2016/03/13/ember-data-2-4-released.html#toc_fastboot-support&quot;&gt;as of 2.4.0&lt;/a&gt;, works with FastBoot with little
configuration (you need to provide the &lt;code&gt;host&lt;/code&gt; to your adapter for now,
as relative URLs do not work for FastBoot&amp;#39;s AJAX layer).  There is a
&lt;a href=&quot;https://github.com/tildeio/ember-cli-fastboot/pull/121&quot;&gt;FastBoot service available to your Ember app that gives you access to
cookies&lt;/a&gt;, &lt;a href=&quot;https://github.com/tildeio/ember-cli-fastboot/pull/123&quot;&gt;headers&lt;/a&gt; and &lt;a href=&quot;https://github.com/tildeio/ember-cli-fastboot/pull/136&quot;&gt;the requested host in the FastBoot version of your
application&lt;/a&gt;. DockYard.com may be a bit on the bleeding edge, but a
production version of FastBoot is not that far off.&lt;/p&gt;

&lt;p&gt;If you and your company are looking for help getting your application
FastBoot ready we&amp;#39;d love to help. &lt;a href=&quot;https://dockyard.com/contact/hire-us&quot;&gt;Please reach out to us&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Prefer Integration Tests over Acceptance Tests</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/28/prefer-integration-tests" />
    <id>https://dockyard.com/blog/2016/03/28/prefer-integration-tests</id>
    <category term="javascript" label="JavaScript"/><category term="testing" label="Testing"/><category term="ember" label="Ember.js"/>
    <published>2016-03-28 00:00:00</published>
    <updated>2016-03-28 17:09:32</updated>
    <author><name>Marten Schilstra</name></author>
    <summary>Integration testing should be an integral part of your test suite.</summary>
    <content type="html">&lt;p&gt;It is suprisingly easy to test your whole Ember.JS application using acceptance tests only. All you have to do is to reproduce how you would normally navigate through the application using a &lt;a href=&quot;https://guides.emberjs.com/v2.4.0/testing/acceptance/&quot;&gt;stellar set of helpers&lt;/a&gt;. Don&amp;#39;t want to test your API? &lt;a href=&quot;http://www.ember-cli-mirage.com&quot;&gt;Add ember-cli-mirage&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;You should realize though, that each acceptance test boots up the whole Ember.JS application and starts you at the &lt;code&gt;application.index&lt;/code&gt; route. You then have to navigate to the right page and then test the thing you wanted to do. This is fine when you want to test a complex user-flow through an app, but a big waste of time and CPU cycles to verify if a form submit button is unclickable when the data is invalid.&lt;/p&gt;

&lt;p&gt;If you create acceptance tests for every edge case and every regression, then it will be likely that your test suite will quickly grow to be five, ten or more minutes long. That is a problem since slow test suites are likely to be run less often by the developer, and test failures won&amp;#39;t be caught quickly. I have caught myself relying on the CI server to run the tests for me, while doing other stuff, because I didn&amp;#39;t want to wait for just five minutes.&lt;/p&gt;

&lt;p&gt;Having said all that, I think we should write more integration tests and less acceptance tests. Integration tests in most cases run much faster, because you don&amp;#39;t have to boot a whole app, or navigate to the page where your component is being used.&lt;/p&gt;

&lt;p&gt;Integration tests are also more flexible than most people think. They&amp;#39;re not only for testing components, you can also test &lt;a href=&quot;https://github.com/DockYard/ember-composable-helpers/blob/master/tests/integration/helpers/map-by-test.js&quot;&gt;template helpers&lt;/a&gt;. Actually you can test anything with an &lt;a href=&quot;https://github.com/switchfly/ember-test-helpers/blob/master/lib/ember-test-helpers/test-module.js#L26&quot;&gt;integration test&lt;/a&gt;. For example a model that has logic depending on its relationships is a good example where you can use a non-component integration test.&lt;/p&gt;

&lt;p&gt;Using component integration tests to test components should also improve your component design. Test driving individual components will make you think more about their external API, prevents building a &lt;a href=&quot;http://slides.com/miguelcamba/composable-components#/8&quot;&gt;LMAO&lt;/a&gt; and promotes &lt;a href=&quot;https://en.wikipedia.org/wiki/Loose_coupling&quot;&gt;loose coupling&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is, however, a small downside to integration tests: the API for writing component integration tests is completely different than the api for writing acceptance tests, so you will have to learn another totally different style of writing tests while maintaining the knowledge of how to write acceptance tests. Luckily there is a &lt;a href=&quot;https://github.com/emberjs/rfcs/pull/119&quot;&gt;motion to unify&lt;/a&gt; the API for integration and acceptance tests.&lt;/p&gt;

&lt;p&gt;If you aren&amp;#39;t that familiar with EmberJS&amp;#39; integration tests I&amp;#39;d recommend to read Alisdair McDiarmid&amp;#39;s &lt;a href=&quot;https://alisdair.mcdiarmid.org/ember-component-integration-tests/&quot;&gt;Ember component integration tests&lt;/a&gt; post.&lt;/p&gt;

&lt;p&gt;Closing out I&amp;#39;d like to say that this post isn&amp;#39;t mean&amp;#39;t to say don&amp;#39;t do any acceptance testing anymore. Acceptance tests are still necessary to smoke test the whole application.&lt;/p&gt;
</content>
  </entry><entry>
    <title>What makes Phoenix Presence special, and a sneak peek</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/25/what-makes-phoenix-presence-special-sneak-peek" />
    <id>https://dockyard.com/blog/2016/03/25/what-makes-phoenix-presence-special-sneak-peek</id>
    <category term="elixir" label="Elixir"/><category term="presence" label="Presence"/><category term="phoenix" label="Phoenix"/>
    <published>2016-03-25 00:00:00</published>
    <updated>2016-03-25 17:52:22</updated>
    <author><name>Chris McCord</name></author>
    <summary>Phoenix Presence brings cutting edge features unmatched by other frameworks. Find out how with a sneak peek.</summary>
    <content type="html">&lt;p&gt;At DockYard, our goal is to build the fastest and most robust
applications for our clients both on the front-end and back-end. When
it comes to the server, Elixir and Phoenix give us the fastest
platform with the highest productivity. And it just keeps getting
better. New features like the much anticipated Phoenix Presence have
us extremely excited about treading new ground on what a Web framework
can accomplish.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s a sneak peek of the new features in action that show how we&amp;#39;re
putting cutting edge CS research into practice and how you can try it out for yourself.
Jump below for full details:&lt;/p&gt;

&lt;iframe width=&quot;420&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/9dALrnCOLNE&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;h3&gt;Phoenix Presence&lt;/h3&gt;

&lt;p&gt;Phoenix Presence is an upcoming feature in Phoenix 1.2 which brings
support for registering process information on a topic and replicating
this information transparently across a cluster. Its simplest use-case
would be showing which users are currently online in an application,
but we&amp;#39;re excited about other lower-level uses such as service
discovery. This feature at first seems simple and mundane, but most
libraries fail to properly tackle it and those that do introduce extra
dependencies without solving edge-cases. Not so with Phoenix.&lt;/p&gt;

&lt;h3&gt;What makes it special?&lt;/h3&gt;

&lt;p&gt;What&amp;#39;s special about Phoenix&amp;#39;s implementation is we have a system that
applies cutting edge CS research to tackle day-to-day problems in the
applications we all write. Phoenix Presence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;has no single point of failure&lt;/li&gt;
&lt;li&gt;has no single source of truth&lt;/li&gt;
&lt;li&gt;relies entirely on the standard library with no operational
dependencies&lt;/li&gt;
&lt;li&gt;self heals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike most libraries and web frameworks in various languages, Phoenix
does not require a central datastore to hold presence information.
While having to deploy Redis or similar datastores increases your
operational overhead, it also introduces a couple severe penalties â a
single point of failure, and central bottleneck. Worse still, if one
of your servers goes down, you&amp;#39;ll have orphaned data stuck permanently
in your database. With Phoenix, we&amp;#39;ve developed a system based on a
distributed heartbeat/gossip protocol which uses a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type&quot;&gt;CRDT&lt;/a&gt;
to replicate data in a conflict-free way. This gives you high
availability and performance because we don&amp;#39;t have to send all data
through a central server. It also gives you resilience to failure
because the system &lt;em&gt;automatically recovers from failures&lt;/em&gt;. This
includes other nodes going up or down or spotty networks causing
netsplits and missed data replication.&lt;/p&gt;

&lt;h3&gt;Great platforms yield great solutions&lt;/h3&gt;

&lt;p&gt;None of this would be possible without the innovations from Elixir and
Erlang which gives us a distributed runtime that&amp;#39;s unmatched by other
languages. When we sat down to design Phoenix Presence, instead of
immediately asking &amp;quot;which database would be best to hold presences?&amp;quot;,
we could ask &amp;quot;how can we best replicate data in a distributed system
without the user having to worry about it?&amp;quot;. The platforms you build
on top of drive the design decisions you make in your products. With
Elixir, you are empowered to tackle problems that in other platforms
would feel impossible to solve without tradeoffs with heavy dependencies.
Overtime these decisions play out to more reliable products and services, 
and better user experiences.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Testing function delegation in Elixir without stubbing</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/24/testing-function-delegation-in-elixir-without-stubbing" />
    <id>https://dockyard.com/blog/2016/03/24/testing-function-delegation-in-elixir-without-stubbing</id>
    <category term="testing" label="Testing"/><category term="elixir" label="Elixir"/><category term="engineering" label="Engineering"/>
    <published>2016-03-24 00:00:00</published>
    <updated>2016-03-25 15:45:24</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;In other lanugages mocking/stubbing are part of your regular toolbelt, in Elixir Jose has
come out against them &lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;I will fight against mocks, stubs and YAML in Elixir with all my... friendliness and energy to promote proper education on those topics.&lt;/p&gt;&amp;mdash; JosÃ© Valim (@josevalim) &lt;a href=&quot;https://twitter.com/josevalim/status/641617411242913792&quot;&gt;September 9, 2015&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;Instead he suggests&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/bcardarella&quot;&gt;@bcardarella&lt;/a&gt; for tests, create a simple module (or an agent if you need flexibility) that will be used by your app during your tests&lt;/p&gt;&amp;mdash; JosÃ© Valim (@josevalim) &lt;a href=&quot;https://twitter.com/josevalim/status/641619543543152640&quot;&gt;September 9, 2015&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;I&amp;#39;ve been trying to practice this until the other day when I was
building a library that was adapter based. I wanted to unit test the
parent module that would delegate to the adapter. The adapters can
change and I don&amp;#39;t want the unit test of the parent module to be tied to
any particular child. As a matter of example, we could have something
like this:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule Parent do
  defmacro __using__([adapter: adapter]) do
    quote do
      def __adapter__, do: unquote(adapter)
      def make_it_so(command) do
        __adapter__.make_it_so(command)
      end
    end
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In other languages I would stub out &lt;code&gt;Parent.make_it_so/1&lt;/code&gt; and assert that
this function was being called. For example, if you were using the
&lt;a href=&quot;https://github.com/jjh42/mock&quot;&gt;&lt;code&gt;mock&lt;/code&gt;&lt;/a&gt; Elixir library you would do:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule CustomParent do
  use Parent, adapter: FooBar
end

with_mock CustomParent, [make_it_so: fn(command) -&amp;gt; command end] do
  CustomParent.make_it_so(:ok)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;But as Jose has pointed out we don&amp;#39;t want to do this.
So how do we test that the adapter&amp;#39;s &lt;code&gt;make_it_so/1&lt;/code&gt; function is being
properly delegated to without stubbing? Well we can rely on Elixir&amp;#39;s
&lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Process.html#send/3&quot;&gt;&lt;code&gt;send/3&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://elixir-lang.org/docs/stable/ex_unit/ExUnit.Assertions.html#assert_receive/3&quot;&gt;&lt;code&gt;assert_receive&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Keep in mind that &lt;code&gt;send&lt;/code&gt; will allow you to put messages into a process&amp;#39;s
mailbox and &lt;code&gt;assert_receive&lt;/code&gt; will allow you to test against that.&lt;/p&gt;

&lt;p&gt;Here is how you might test the delegation:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule ParentTest do
  use ExUnit.Case

  defmodule CustomAdapter do
    def make_it_so(_command) do
      send self(), :ok
    end
  end

  defmodule CustomParent do
    use Parent, adapter: CustomAdapter
  end

  test &amp;quot;delegates to the adapter&amp;quot; do
    CustomParent.make_it_so(%{foo: &amp;quot;bar&amp;quot;})

    assert_receive :ok
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And that&amp;#39;s it. You can handle more complex situations by adding your own
logic inside the &lt;code&gt;CustomAdapter&lt;/code&gt;s function, to send or not send
depending upon the value passed in but that should depend upon your
use-case.&lt;/p&gt;

&lt;p&gt;So what happens when you are testing with a module that might spawn its
own process? In those cases I might have an &lt;code&gt;opts&lt;/code&gt; argument that I can
work with. Let&amp;#39;s assume that for whatever reason &lt;code&gt;Parent.make_it_so&lt;/code&gt;
is working in a process on its own:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule ParentTest do
  use ExUnit.Case

  defmodule CustomAdapter do
    def make_it_so(_command, opts) do
      send opts[:pid], :ok
    end
  end

  defmodule CustomParent do
    use Parent, adapter: CustomAdapter
  end

  test &amp;quot;delegates to the adapter&amp;quot; do
    opts = [pid: self()]
    CustomParent.make_it_so(%{foo: &amp;quot;bar&amp;quot;}, opts)

    assert_receive :ok
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This works because each test in &lt;code&gt;ExUnit&lt;/code&gt; runs in its own process. You
could even do this in a &lt;code&gt;setup&lt;/code&gt; block if you needed to capture the PID
for many tests. However, you cannot do this in &lt;code&gt;setup_all&lt;/code&gt; as that runs
in a different process than the individual tests.&lt;/p&gt;

&lt;p&gt;Testing in Elixir has been fun as it has forced me to think about things
differently than I&amp;#39;ve been used to over the past few years. If this
topic is of interest to you check out my talk from &lt;a href=&quot;http://elixirdaze.com&quot;&gt;ElixirDaze&lt;/a&gt; on Building and Testing
Phoenix APIs&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot;
src=&quot;https://www.youtube.com/embed/zoP-XFuWstw&quot; frameborder=&quot;0&quot;
allowfullscreen&gt;&lt;/iframe&gt;
</content>
  </entry><entry>
    <title>The things about Red, Green, Refactor that nobody ever talks about</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/23/the-thing-about-red-green-refactor-nobody-talks-about" />
    <id>https://dockyard.com/blog/2016/03/23/the-thing-about-red-green-refactor-nobody-talks-about</id>
    <category term="opinion" label="Opinion"/><category term="engineering" label="Engineering"/><category term="best-practices" label="Best Practices"/>
    <published>2016-03-23 00:00:00</published>
    <updated>2016-03-24 19:05:47</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/acmyARH.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;&amp;quot;Red&amp;quot;, &amp;quot;Green&amp;quot;, &amp;quot;Refactor&amp;quot;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Red&lt;/em&gt;, &lt;em&gt;Green&lt;/em&gt;, &lt;em&gt;Refactor&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RED&lt;/strong&gt; &lt;strong&gt;GREEN&lt;/strong&gt; &lt;strong&gt;REFACTOR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This process has been drilled into our head for over ten years. The goal
is to push to writing better software by ensuring that only what you
have spec&amp;#39;d out is implemented. The problem however is when you&amp;#39;re in
new territory. In order to write proper tests you need to have an
understanding of the system it is spec&amp;#39;ing. If the implementation of
that system is still a mystery then you can find yourself getting
blocked trying to dream up how to test a system you have no idea is
going to work.&lt;/p&gt;

&lt;p&gt;Does this sound familiar?&lt;/p&gt;

&lt;p&gt;The dogmatic approach of Red, Green, Refactor can sometimes be a
blocker. If it is preventing you from delivering business value what
good is it doing?&lt;/p&gt;

&lt;p&gt;Well, I&amp;#39;ve got some secrets to share about Red, Green, Refactor...&lt;/p&gt;

&lt;h3&gt;It&amp;#39;s OK to spike the implementation first&lt;/h3&gt;

&lt;p&gt;When trying to implement something new writing the actual implementation
is sometimes easier than reasoning about how to test said system. In
these cases it is perfectly reasonable to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Code spike the implementation&lt;/li&gt;
&lt;li&gt;Gain knowledge on what the boundaries and requirements of the implementation are&lt;/li&gt;
&lt;li&gt;Toss out the spiked code&lt;/li&gt;
&lt;li&gt;Write the tests&lt;/li&gt;
&lt;li&gt;Write the new implementation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;More often than not you&amp;#39;ll find this strategy to be very effective and
you&amp;#39;ll break through the wall faster than attempting to dream up the
implementation in your head before writing the tests. You may also find
that when you get to Step 5 the re-implemented code is much better than
the spike you originally wrote.&lt;/p&gt;

&lt;h3&gt;You don&amp;#39;t have to follow any &amp;quot;order&amp;quot;&lt;/h3&gt;

&lt;p&gt;Take a look at the graph at the top of the page. Where does it start?
Where does it end? Most people, because of the phrase &amp;quot;Red, Green,
Refactor&amp;quot; feel they &lt;em&gt;must&lt;/em&gt; start with &amp;quot;Red&amp;quot;. Well, you don&amp;#39;t. Let&amp;#39;s
assume you inherit an application that has poor, or no, test coverage.
It&amp;#39;s perfectly OK to write simple acceptance tests that assert the
current behavior of the application. Go directly to &amp;quot;Green&amp;quot;. This is OK
because the application is already live, it&amp;#39;s working. Once you have the
happy paths covered in the acceptance tests you&amp;#39;ve written you can
refactor with confidence.&lt;/p&gt;

&lt;h3&gt;Break the &amp;quot;rules&amp;quot;&lt;/h3&gt;

&lt;p&gt;Like most rules &amp;quot;Red, Green, Refactor&amp;quot; makes sense for most cases, but
not all. In situations where you find yourself restricted or not moving forward
feel free to break the rules until you can get back to a place where
observing them again makes sense.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember&#39;s getWithDefault</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/18/get-with-default" />
    <id>https://dockyard.com/blog/2016/03/18/get-with-default</id>
    <category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/><category term="best-practices" label="Best Practices"/>
    <published>2016-03-18 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Michael Dupuis</name></author>
    <summary>A quick look at a common gotcha.</summary>
    <content type="html">&lt;h2&gt;Getting Default Values&lt;/h2&gt;

&lt;p&gt;Here&amp;#39;s a quick look at a common gotcha that slips into pull requests
from time to time.&lt;/p&gt;

&lt;p&gt;When working in Ember, you&amp;#39;ll often want a default value for
certain properties. Ember provides a convenient means for getting a
default value with the aptly named, &lt;a href=&quot;https://github.com/emberjs/ember.js/tree/v2.4.0/packages/ember-metal/lib/property_get.js#L152&quot;&gt;&lt;code&gt;getWithDefault&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Ember.getWithDefault(person, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Doe&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above code would retrieve the &lt;code&gt;lastName&lt;/code&gt; property off of the
&lt;code&gt;person&lt;/code&gt; object, and if the value is &lt;code&gt;undefined&lt;/code&gt;, it will return
&lt;code&gt;Doe&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;An Example&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s say we&amp;#39;re working on a campaign application with a &lt;code&gt;Donation&lt;/code&gt; model. This
app will primarily be used by &lt;a href=&quot;https://www.opensecrets.org/pacs/superpacs.php&quot;&gt;Super PACs&lt;/a&gt; to fund campaigns
of legislators who represent the interests of a small group of deep-pocketed
individuals. These well-funded legislators will &lt;a href=&quot;http://www.opensecrets.org/news/2008/11/money-wins-white-house-and/&quot;&gt;win their elections
about 90% of the time&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Naturally, if the donor does not disclose her name, 
the Super PACs would like the default donation to display &amp;quot;Anonymous.&amp;quot;&lt;/p&gt;

&lt;p&gt;Our first pass looks something like this:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// app/donation/model.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Model from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data/model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; attr from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data/attr&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; computed from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-computed&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; get from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-metal/get&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Model.extend({
  &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;fullName&lt;/span&gt;: attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),

  &lt;span class=&quot;key&quot;&gt;displayName&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) || &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Anonymous&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
    }
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We soon realize we can clean up our &lt;code&gt;displayName&lt;/code&gt; computed property with &lt;code&gt;getWithDefault&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;displayName: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  get() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; getWithDefault(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Anonymous&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Using &lt;code&gt;getWithDefault&lt;/code&gt; in that example is a bit cleaner and easier to
read.&lt;/p&gt;

&lt;p&gt;Then one day, we wire up with a new, external API. The JSON payload from this backend
sends &lt;code&gt;null&lt;/code&gt; for &lt;code&gt;fullName&lt;/code&gt; if the record does not have a
value. Our &lt;code&gt;displayName&lt;/code&gt; no longer defaults to &amp;quot;Anonymous&amp;quot; and we&amp;#39;re
slightly confused. If our &lt;code&gt;fullName&lt;/code&gt; value is falsy, why does
&lt;code&gt;getWithDefault&lt;/code&gt; not return our default value?&lt;/p&gt;

&lt;p&gt;Remember, &lt;code&gt;getWithDefault&lt;/code&gt; is not evaluating
whether or not the return value is truthy or falsy: it only returns the
default value if the &lt;code&gt;get&lt;/code&gt; returns &lt;code&gt;undefined&lt;/code&gt;. The value that was once
&lt;code&gt;undefined&lt;/code&gt; is now &lt;code&gt;null&lt;/code&gt;, so &lt;code&gt;getWithDefault&lt;/code&gt; returns &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The solution here is probably to cleanup the JSON payload in the
serializer so that &lt;code&gt;null&lt;/code&gt; values are treated as &lt;code&gt;&amp;#39;&amp;#39;&lt;/code&gt;. 
But for this contrived example, and for any instance in
which you would like to set a default value based off a falsy return
value, use a good, old-fashioned &lt;code&gt;or&lt;/code&gt; operator:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;displayName: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  get() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) || &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Anonymous&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
  }
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I hope this prevents a few people from scratching their heads when
&lt;code&gt;getWithDefault&lt;/code&gt; doesn&amp;#39;t behave as expected.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and
don&amp;#39;t forget to support campaign finance reform this tax season by
opting into the &lt;a href=&quot;https://en.wikipedia.org/wiki/Presidential_election_campaign_fund_checkoff&quot;&gt;Presidential Election Campaign Fund&lt;/a&gt; (it&amp;#39;s free)!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Why?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/17/why" />
    <id>https://dockyard.com/blog/2016/03/17/why</id>
    <category term="project-management" label="Project Management"/><category term="agile" label="Agile"/><category term="product-management" label="Product Management"/><category term="development" label="Development"/>
    <published>2016-03-17 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Jon Lacks</name></author>
    <summary>Don&#39;t underestimate the power of this simple question</summary>
    <content type="html">&lt;p&gt;Just the other day amidst working on what would be classified as a longer term client engagement for DockYard, I was reminded of the power of âWhyâ.  One of the most wonderful things about being human (and what separates us from machines) is that we are motivated by many different things both in our personal and professional lives.  &lt;/p&gt;

&lt;p&gt;When it comes to working on projects which involve the design &amp;amp; development of a product not owned by our company, itâs easy to get stuck in a rut of just churning out âDeliverablesâ and forgetting what you&amp;#39;re actually contributing to in the greater scheme of things.    A good work environment, generous compensation and work life balance can only go so far.  High performing teams also need to know and feel that they are contributing to the world they live in - sometimes in an evolutionary way and sometimes a very revolutionary way. &lt;/p&gt;

&lt;p&gt;One important distinction which sometimes gets missed - âwhyâ is very different from âhowâ.  âHowâ is much more easily defined.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How = adverb. In what way or manner; by what means.&lt;/li&gt;
&lt;li&gt;Why = adverb. For what reason or purpose.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It might come as a surprise to some of our clients how personally vested we get in their products even though we may be acting as supporting cast.  You have to consider that we essentially live and breathe our clientsâ products while they are in development.  We think about it during our workday, we think about it while commuting and we think about while taking a shower - TMI perhaps!  After many months of contributing to a product&amp;#39;s evolution, to maintain motivation, we must remind ourselves âWhyâ we are there in the first place.&lt;/p&gt;

&lt;p&gt;Passionate product owners are those who always provide their team with a compass heading towards an eventual goal. The path to get there is twisty and bumpy but at end of the day the team knows what the end game looks like and how it contributes to the world.    As an agency we are always looking to amplify this real-world connection for our team members  to make sure they feel aligned with the overall product objective.  Our Project Management team at DockYard shouldered this responsibility, making sure they stay aligned to our clientsâ compass throughout the project journey.  This will no doubt allow our team to better navigate that twisty/bumpy path towards the overall product objective while at the same time providing a motivating work environment for our most valued company resource: the employees.&lt;/p&gt;
</content>
  </entry><entry>
    <title>A learning experience in web application design (part 1 of 2)</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/11/a-learning-experience-in-web-application-design-part-1" />
    <id>https://dockyard.com/blog/2016/03/11/a-learning-experience-in-web-application-design-part-1</id>
    <category term="design-process" label="Design Process"/><category term="design" label="Design"/><category term="design-thinking" label="Design Thinking"/>
    <published>2016-03-11 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Chris Bowers</name></author>
    <summary>A speculative project that would challenge me to confront the differences between print and web application design.</summary>
    <content type="html">&lt;p&gt;After a summer of freelance magazine work, I joined the DockYard design team. This has required my design practice to evolve. My education and experience in editorial and publication design made me comfortable with visual systems and hierarchyâa skill fundamental to any design project. Yet, shifting my focus to UI involves working through a new set of problems. &lt;/p&gt;

&lt;p&gt;Even though I use web applications daily, it doesnât mean I understand every crucial detail that makes a successful interface. I know when a design doesnât work, but the thing about good UI is that it can slip right by you. If you asked me what the loading state for tumblr was, I would have to go and check even though I see it everyday. &lt;/p&gt;

&lt;p&gt;A common idea in UI design is to fail fast and iterate often. Understanding means nothing without experience. With this in mind, I chose to design the UI for a speculative project that would challenge me to confront the differences between print and web application design.&lt;/p&gt;

&lt;p&gt;Designing for the user, not for yourself almost seems like a new concept born out of interaction design, but editorial is no stranger to this ideology. Just like with any web application, a magazineâs user needs to be able to absorb the important information quickly and navigate seamlessly. Good print design is consistent with grid, type, and color choices. This consistency provides a level of comfort for the user. &lt;/p&gt;

&lt;p&gt;Unlike a magazine, an application should provide constant feedback to communicate with its user. Every action needs an appropriate reaction to simplify and support the userâs journey. Interface responses manifest themselves in different component states. âWhy is this taking so long?â is met with a skeleton UI that makes the application appear faster than it is. Answering a userâs instinctive questions lets the brain focus on the task at hand. &lt;/p&gt;

&lt;p&gt;For this project, I focused on a concept for a produce delivery service from &lt;a href=&quot;http://www.creativebloq.com/web-design/design-single-page-app-ember-121518402&quot;&gt;an article by Steven Trevathan&lt;/a&gt;. Working on this app gave me a chance to explore different states and forms of feedback for many application components. For a range of different states, I planned to design the components shown below.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/G0ZEL3x.jpg&quot; alt=&quot;Components&quot;&gt;&lt;/p&gt;

&lt;p&gt;To guide this project, I referenced &lt;a href=&quot;https://medium.com/swlh/the-nine-states-of-design-5bfe9b3d6d85#.agxc5g36b&quot;&gt;The Nine States of Design article&lt;/a&gt; by Vince Speelman. Given that these states are a necessity for any web application, the exciting part is experimenting with the form and language of them. My next post will show my own process designing states that align with a specific brand personality. Well crafted states can give the user an experience to enjoy and not just tolerate, even when they deviate from the intended path. &lt;/p&gt;
</content>
  </entry><entry>
    <title>How we taught an intro to UX design workshop</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/08/how-we-taught-an-intro-to-ux-design-workshop" />
    <id>https://dockyard.com/blog/2016/03/08/how-we-taught-an-intro-to-ux-design-workshop</id>
    <category term="community" label="Community"/><category term="training" label="Training"/><category term="ux-design" label="Ux Design"/><category term="design" label="Design"/><category term="user-experience" label="User Experience"/>
    <published>2016-03-08 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Earlier this week, Amanda and I taught a workshop for the Northeastern University Women in Tech group.</summary>
    <content type="html">&lt;p&gt;Earlier this week, my colleague &lt;a href=&quot;https://twitter.com/acacheung&quot;&gt;Amanda&lt;/a&gt; and I taught a workshop for the
&lt;a href=&quot;http://nuwit.ccs.neu.edu/index.html&quot;&gt;Northeastern University Women in Tech
group&lt;/a&gt;. More than 35 computer
science majors, as well as designers and inter-media studies students
joined us for two hours of hands-on learning.&lt;/p&gt;

&lt;p&gt;By presenting this workshop, we got a chance to meet and collaborate
with a great bunch of motivated students, and learned a few things
ourselves!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/aTVPBvY.jpg&quot; alt=&quot;Workshop participants&quot;&gt;&lt;/p&gt;

&lt;h2&gt;You can learn fast when you start with a common background&lt;/h2&gt;

&lt;p&gt;A big portion of the workshop consisted of a hands-on exercise:
the participants conducted &lt;a href=&quot;https://dockyard.com/design-sprints&quot;&gt;design sprints&lt;/a&gt; from user interviews to screen
flows. The constraints were that our audience was generally new to UX
design and the workshop was to fit in a one hour timeframe. We started
with an &lt;a href=&quot;https://speakerdeck.com/rgbcolor/intro-to-ux-design-a-dockyard-workshop&quot;&gt;introductory UX design presentation&lt;/a&gt; and then posed our workshop
prompt. The hypothetical client and problem set was intimately familiar
to all of the participants: the Boston MBTA.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/YKLlo6u.jpg&quot; alt=&quot;Workshop participants&quot;&gt;&lt;/p&gt;

&lt;p&gt;Participants switched between end-user and interviewer roles, and
conducted quick interviews to find problems to solve. The process went
very smoothly and had quite a few laughs, as we all shared painful
experiences weâve all had on the clunky and crowded transit system.&lt;/p&gt;

&lt;h2&gt;When in doubt, propose a magical solution&lt;/h2&gt;

&lt;p&gt;Because the goal of the workshop was an introduction to the whole UX
design process, rather than a refinement of a particular skill, we
decided to move away from any potential time-consuming sticking points
like detailed research or gathering real data.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/9O8LN7G.jpg&quot; alt=&quot;UX Design workshop&quot;&gt;&lt;/p&gt;

&lt;p&gt;Our demo: the low-fidelity presentation of UX problems and solutions for
a unicorn to find a compatible public transit car.&lt;/p&gt;

&lt;p&gt;As an example outcome, we demonstrated a UX design proposal that solves
the problem a unicorn might have when she doesnât know if a
unicorn-compatible train car is available on the MBTA. This is clearly
not a practical design premise. What it is, is a story so ridiculous and
open to interpretation that it gives participants the license to invent
a solution, however crazy, rather than get stuck in the process. As a
result, folks were able to improvise solutions quickly.&lt;/p&gt;

&lt;h2&gt;Present what youâve learned&lt;/h2&gt;

&lt;p&gt;Hands-on learning seems like the best method to internalize new concepts
quickly. But to really make sure that our participants are able to
remember and apply their new UX design skills in their work going
forward, we asked them to present their findings at the end of the
workshop. Each team of 5-6 people was asked to pitch their app proposal
to the entire group. They had to explain each proposed interface
solution by stating what user problem they had discovered through
interviews, and how the interface would address that problem.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/j0ss1Zn.jpg&quot; alt=&quot;Workshop participants&quot;&gt;&lt;/p&gt;

&lt;p&gt;By âpitchingâ UX design considerations for the fictional MBTA app, the
participants got practice and gained confidence to do it again in a
future project.&lt;/p&gt;

&lt;h2&gt;Whatâs next&lt;/h2&gt;

&lt;p&gt;In the follow-up discussion, a participant asked what the next step
might be for someone learning UX design for the first time. We did not
have a prepared answer at the time, except for this: &lt;strong&gt;anyone can and
should include UX design considerations at the beginning of any project
to save time and effort&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is a list of actionable items to further your initial set of skills
so you can start including UX in projects in any discipline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Join UX-oriented Meetups and learn through presentations, networking,
workshops, and panel discussions. DockYard hosts &lt;a href=&quot;http://www.meetup.com/UX-East/&quot;&gt;UX
East&lt;/a&gt;, which includes quarterly
workshops, plus other educational events.&lt;/li&gt;
&lt;li&gt;  Watch &lt;a href=&quot;https://www.youtube.com/watch?v=Ovj4hFxko7c&quot;&gt;this great introductory
video&lt;/a&gt; thatâs drawn on a
whiteboard!&lt;/li&gt;
&lt;li&gt;  Read this article on &lt;a href=&quot;http://www.wired.com/2015/12/simplicity-is-overrated-in-ux-design/&quot;&gt;Simplicity vs. clarity in UX Design by Robert
Hoekman
Jr.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;  Read IDEOâs primer on Design Thinking, &lt;a href=&quot;http://www.designkit.org/resources/1&quot;&gt;The Field Guide to Human Centered
Design&lt;/a&gt;, available in print or as a free PDF&lt;/li&gt;
&lt;li&gt;  Read Erika Hallâs A Book Apart book, &lt;a href=&quot;https://abookapart.com/products/just-enough-research&quot;&gt;Just Enough
Research&lt;/a&gt;, a solid
introduction to the whyâs and howâs of design research&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;This was fun. Letâs do it again!&lt;/h2&gt;

&lt;p&gt;The workshop results surpassed our expectation: every group put together
a fun, articulate presentation with their UX considerations for a
fictional app. We saw many fun creative ideas, as well as âahaâ moments
where an obvious problem and a simple solution found a match. We had a
great group of students, and saw a lot of results in the two hours they
invested into learning with us.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/3WkjbBS.jpg&quot; alt=&quot;UX Design example&quot;&gt;&lt;/p&gt;

&lt;p&gt;The creatively named âMBT-Yayâ app&lt;/p&gt;

&lt;h2&gt;Interested in hands-on learning?&lt;/h2&gt;

&lt;p&gt;If you and your team are curious about hands-on workshops, and would
like to chat to one of us about potentially hosting one, get in touch!
&lt;a href=&quot;mailto:maria.matveeva@dockyard.com&quot;&gt;Weâd love to collaborate&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>TIL: Elixir maps have built in syntax for updating</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/03/07/til-elixir-maps-have-built-in-syntax-for-updating" />
    <id>https://dockyard.com/blog/2016/03/07/til-elixir-maps-have-built-in-syntax-for-updating</id>
    <category term="til" label="Til"/><category term="elixir" label="Elixir"/>
    <published>2016-03-07 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Marin Abernethy</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I am relatively new to Elixir and often find there are numerous ways to
implement a single task. For example, when I want to update a key value in a map, I have several options before me...&lt;/p&gt;

&lt;p&gt;Given, &lt;code&gt;expenses = %{groceries: 200, rent: 1000, commute: 70}&lt;/code&gt;, I could
employ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Map.html#merge/2&quot;&gt;&lt;code&gt;Map.merge(map1, map2)&lt;/code&gt;&lt;/a&gt; if I want to update multiple key value pairs
and/or several new ones&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Map.merge(expenses, %{
  rent: 1200,
  comcast: 100
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Map.html#put/3&quot;&gt;&lt;code&gt;Map.put(map, key, val)&lt;/code&gt;&lt;/a&gt; if updating or adding a single key value&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Map.put(expenses, :booze, 100)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Map.html#update/4&quot;&gt;&lt;code&gt;Map.update(map, key, initial, fun)&lt;/code&gt;&lt;/a&gt;: if I want to increment a value by a certain degree&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Map.update(expenses, :misc, 300, &amp;amp;(&amp;amp;1 * 2))
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Kernel.html#put_in/3&quot;&gt;&lt;code&gt;Kernel.put_in(data, keys, value)&lt;/code&gt;&lt;/a&gt;: if I want to update a value in a nested structure&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;expenses = %{groceries: %{milk: 5}, apartment: %{rent: 1000, comcast: 100}}
put_in(expenses, [:rent, :comcast], &amp;quot;too much&amp;quot;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;However, &lt;strong&gt;today I learned&lt;/strong&gt;, maps come with a built in syntax for updating
one or more key values!&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt; %{expenses | groceries: 150, commute: 75}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;While a bit obscure, and not easily found in the &lt;a href=&quot;http://elixir-lang.org/docs.html&quot;&gt;elixir docs&lt;/a&gt;, this trick is definitely nice to have in my elixir tool belt. The only thing to remember is that this syntax requires &lt;code&gt;groceries&lt;/code&gt; and &lt;code&gt;commute&lt;/code&gt;
to already exist. Otherwise, it will fail with an error. Hopefully, this syntax comes in handy for you now too!&lt;/p&gt;

&lt;p&gt;If you want to know more about how to deal with nested structures, check out Brian&amp;#39;s post &lt;a href=&quot;https://dockyard.com/blog/2016/02/01/elixir-best-practices-deeply-nested-maps&quot;&gt;&amp;quot;Elixir Best Practices - Deeply Nested Maps&amp;quot;&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Code Linting: An Inside Look</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/29/code-linting-inside-look" />
    <id>https://dockyard.com/blog/2016/02/29/code-linting-inside-look</id>
    <category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/>
    <published>2016-02-29 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Estelle DeBlois</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;A little while back, I wrote a &lt;a href=&quot;https://dockyard.com/blog/2015/08/07/suave-up-your-code&quot;&gt;blog post&lt;/a&gt; introducing &lt;a href=&quot;https://github.com/DockYard/ember-suave&quot;&gt;&lt;code&gt;ember-suave&lt;/code&gt;&lt;/a&gt;, an addon that we created at DockYard to help enforce a common code style across all of our projects. With the addon installed, any code that doesn&amp;#39;t align with the established styleguide will cause the build to fail. During development, as files are modified, the linter will reprocess the changed files, displaying errors in the console right away.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;ve adopted &lt;code&gt;ember-suave&lt;/code&gt; in your own projects, you may be content to find that things just work. But there&amp;#39;s a lot of satisfaction to be had with understanding how the addon does what it does.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s start at the core with JSCS.&lt;/p&gt;

&lt;h2&gt;JSCS&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://jscs.info/&quot;&gt;JSCS&lt;/a&gt; is the wonderful library that uses a set of predefined code style rules to lint your code. It comes with a very simple API:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let Checker = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;jscs&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
let checker = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Checker();

checker.registerDefaultRules();

checker.configure({
  &lt;span class=&quot;key&quot;&gt;verbose&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;comment&quot;&gt;// shows rule name next to error messages&lt;/span&gt;
  &lt;span class=&quot;key&quot;&gt;requireSpaceBeforeBinaryOperators&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;requireSpaceAfterBinaryOperators&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As this snippet shows, once you install &lt;a href=&quot;https://www.npmjs.com/package/jscs&quot;&gt;&lt;code&gt;jscs&lt;/code&gt;&lt;/a&gt; from NPM and create a new &lt;code&gt;Checker&lt;/code&gt; instance, all you need to do is register the default JSCS rules and configure which ones to enable. You can now start linting your code:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let results = checker.checkString(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;let x = y+z;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
let errors = results.getErrorList().map((error) =&amp;gt; {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; results.explainError(error);
});
console.log(errors.join(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;));
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Running this example will output the following:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;requireSpaceBeforeBinaryOperators: Operator + should not stick to preceding expression at input :
     1 |let x = y+z;
-----------------^
requireSpaceAfterBinaryOperators: Operator + should not stick to following expression at input :
     1 |let x = y+z;
------------------^
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s as simple as that! Of course, this example is merely checking a String literal. In practice, you would want to check the content of your application files, one at a time. This is where &lt;a href=&quot;https://github.com/kellyselden/broccoli-jscs&quot;&gt;broccoli-jscs&lt;/a&gt; comes in.&lt;/p&gt;

&lt;h2&gt;broccoli-jscs&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;broccoli-jscs&lt;/code&gt; was created by &lt;a href=&quot;https://github.com/kellyselden&quot;&gt;Kelly Selden&lt;/a&gt;, and encompasses both a Broccoli plugin and an Ember CLI addon.&lt;/p&gt;

&lt;p&gt;As a &lt;a href=&quot;https://github.com/broccolijs/broccoli-plugin&quot;&gt;plugin&lt;/a&gt;, &lt;code&gt;broccoli-jscs&lt;/code&gt; implements a &lt;code&gt;JSCSFilter&lt;/code&gt; function that accepts a collection of input nodes, which map to file paths. Each file is read into a string, which is then passed to JSCS&amp;#39;s &lt;code&gt;checkString&lt;/code&gt; method for linting. Every time that you make a change to a file while &lt;code&gt;ember s&lt;/code&gt; is running, the file will be reprocessed by the plugin, and any JSCS errors found will be displayed in the console.&lt;/p&gt;

&lt;p&gt;In addition, &lt;code&gt;JSCSFilter&lt;/code&gt; will generate a test file for every file represented in the input nodes. Given &lt;code&gt;foo/example.js&lt;/code&gt;, the plugin will output a test file named &lt;code&gt;foo/example.jscs-test.js&lt;/code&gt;, with the following content:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;module(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;JSCS - foo&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo/example.js should pass jscs&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  ok(&lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo/example.js should pass jscs.&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;requireSpaceBeforeBinaryOperators: Operator + should not stick to preceding expression at foo/example.js :&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;     1 |let x = y+z;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;-----------------^&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;     2 |&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;requireSpaceAfterBinaryOperators: Operator + should not stick to following expression at foo/example.js :&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;     1 |let x = y+z;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;------------------^&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;     2 |&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If no JSCS errors are found, the test file is still generated, but with a passing assertion: &lt;code&gt;ok(true, /* message */)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As an addon, &lt;code&gt;broccoli-jscs&lt;/code&gt; implements the &lt;code&gt;lintTree&lt;/code&gt; function, which is one of the many hooks that Ember CLI exposes, as a way to extend the core build pipeline. In this case, the function simply creates a new instance of the &lt;code&gt;JSCSFilter&lt;/code&gt; plugin and returns it. Ember CLI will call the hook for every addon discovered inside a project, if it is defined. So if you install &lt;code&gt;broccoli-jscs&lt;/code&gt; as an addon, its &lt;code&gt;lintTree&lt;/code&gt; function will be called on every build or re-build, therefore linting your code every time it changes.&lt;/p&gt;

&lt;p&gt;It is worth mentioning that the &lt;code&gt;JSCSFilter&lt;/code&gt; plugin instance returned by &lt;code&gt;lintTree&lt;/code&gt; is also considered a node (representing the collection of JSCS test files), and this node further serves as an input node to additional plugins along the course of building out the project. For instance, it is passed to &lt;code&gt;broccoli-babel-transpile&lt;/code&gt; to turn ES2015 code into ES5 syntax, then to &lt;code&gt;broccoli-concat&lt;/code&gt; in order to be concatenated with other files and produce a single &lt;code&gt;assets/tests.js&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;So where does &lt;code&gt;ember-suave&lt;/code&gt; fit in this picture?&lt;/h2&gt;

&lt;p&gt;If you install &lt;code&gt;ember-suave&lt;/code&gt;, the Ember CLI addon portion of &lt;code&gt;broccoli-jscs&lt;/code&gt; isn&amp;#39;t used. The goal of &lt;code&gt;ember-suave&lt;/code&gt; is to augment the plugin provided by &lt;code&gt;broccoli-jscs&lt;/code&gt;, by configuring it with a set of rules (both JSCS built-in rules as well as custom ones defined inside of &lt;code&gt;ember-suave&lt;/code&gt;), so you don&amp;#39;t have to do so for each project. As such, it has its own &lt;code&gt;lintTree&lt;/code&gt; implementation that calls out to the &lt;code&gt;JSCSPlugin&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Eager for more?&lt;/h2&gt;

&lt;p&gt;Even though this post focuses on &lt;code&gt;ember-suave&lt;/code&gt;, you can imagine the process being very similar for other linters, such as JSHint or ESLint.&lt;/p&gt;

&lt;p&gt;Understanding the inner workings of a build helps tremendously for various situations: when something breaks, you know where and what to look for. Furthermore, you are now better equipped to build extensions of your own, should the need arise.&lt;/p&gt;

&lt;p&gt;If you found this post informative, and would love to learn more about Ember CLI&amp;#39;s build process, available hooks, and how to use them, &lt;a href=&quot;http://emberconf.com/&quot;&gt;EmberConf&lt;/a&gt; is right around the corner. I&amp;#39;ll be diving more into this topic as part of my talk on &amp;quot;Dissecting an Ember CLI Build&amp;quot;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Route Actions</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/19/best-practices-route-actions" />
    <id>https://dockyard.com/blog/2016/02/19/best-practices-route-actions</id>
    <category term="javascript" label="JavaScript"/><category term="best-practices" label="Best Practices"/><category term="ember" label="Ember.js"/>
    <published>2016-02-19 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Bubble your closure actions to the route instead of the controller.</summary>
    <content type="html">&lt;p&gt;In my &lt;a href=&quot;https://dockyard.com/blog/2015/12/07/best-practices-service-backed-components&quot;&gt;previous post&lt;/a&gt;, I wrote about moving singleton state in Controllers into Services that back components. This means being able to lighten the responsibility of Controllers in your application, and in some cases even remove them completely. However, a common pain point that remains for many is that it isn&amp;#39;t really clear what &lt;em&gt;should&lt;/em&gt; live on a Controller, if anything. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/TgmUDac.png&quot; alt=&quot;controllers are dead&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/locks&quot;&gt;Locks&lt;/a&gt; has written an excellent &lt;a href=&quot;https://locks.svbtle.com/controllers-are-dead-long-life-controllers&quot;&gt;blog post&lt;/a&gt; on this topic. Unless you require query parameters, I&amp;#39;d say that you probably don&amp;#39;t need one. That said, I wouldn&amp;#39;t go out of your way to creatively avoid using Controllers, and would only remove them if it makes sense to do so.&lt;/p&gt;

&lt;h2&gt;Refactoring away from Controllers&lt;/h2&gt;

&lt;p&gt;If you do want to remove Controllers from your application given that they are going to be deprecated and removed in the future, great! &lt;/p&gt;

&lt;p&gt;One of the benefits of removing Controllers is that it reduces the amount of &amp;quot;glue code&amp;quot; you need to write to connect your data (route) and its presentation (components). This means a simpler mental model, and reduces the amount of &amp;quot;Ember&amp;quot; you need to write. Instead, you can rely on regular JavaScript you&amp;#39;re already familiar with to build your applications.&lt;/p&gt;

&lt;h2&gt;Sending closure actions directly to the route&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://dockyard.com/blog/2015/10/29/ember-best-practice-stop-bubbling-and-use-closure-actions&quot;&gt;Closure actions&lt;/a&gt; are probably one of my favorite additions to Ember. Instead of casting string actions into the void and praying that something is listening, we can instead use an action like we would any other JavaScript function. This means that we can do useful things like curry arguments, utilize return values, and all of the other good stuff we expect from a regular JS function call. &lt;/p&gt;

&lt;p&gt;For example, the following action is implicit in that you have no idea where the action actually lives â it could be on a component, controller or route.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! where does `myAction` live? }}
&amp;lt;button {{action &amp;quot;myAction&amp;quot;}}&amp;gt;Do it&amp;lt;/button&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately, Ember&amp;#39;s in a bit of an awkward transition phase right now. Without bringing in an addon (or making a custom helper), it&amp;#39;s not possible to use a closure action directly from the route â it would have to be defined on the Controller. &lt;/p&gt;

&lt;p&gt;If you wanted to remove Controllers from your application, then you would have to resort to using string based actions instead of closure actions. This seems like a lose-lose situation, so I worked together with &lt;a href=&quot;https://twitter.com/rwjblue&quot;&gt;rwjblue&lt;/a&gt; to turn his &lt;a href=&quot;http://jsbin.com/jipani/edit?html,js,output&quot;&gt;jsbin spike&lt;/a&gt; into a working addon.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dockyard/ember-route-action-helper&quot;&gt;&lt;code&gt;ember-route-action-helper&lt;/code&gt;&lt;/a&gt; lets you use closure actions defined on the route in your templates, meaning that many Controllers that only exist to implement actions can now be removed. You can install it today with:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ember install ember-route-action-helper
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And to use it, you can just use &lt;code&gt;route-action&lt;/code&gt; in place of &lt;code&gt;action&lt;/code&gt; inside of your route&amp;#39;s template, like so:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! foo/template.hbs }}
{{foo-bar click=(route-action &amp;quot;updateFoo&amp;quot; &amp;quot;Hello&amp;quot; &amp;quot;world&amp;quot;)}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This addon gives you all the goodness of closure actions, and is a great way of taking steps to future proof your Ember application. When Routable Components do land, and actions work correctly, then upgrading your app simply becomes a search and replace for &lt;code&gt;s/route-action/action&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Power up your Handlebars templates with Helpers&lt;/h2&gt;

&lt;p&gt;Helpers are a really nice way of extracting utility functions that you can use in your application. You can create class based Helpers, like &lt;code&gt;ember-route-action-helper&lt;/code&gt;, or simple pure-function ones using &lt;a href=&quot;http://emberjs.com/api/classes/Ember.Helper.html#method_helper&quot;&gt;&lt;code&gt;Helper.helper&lt;/code&gt;&lt;/a&gt; like the one used in &lt;a href=&quot;https://github.com/poteto/ember-toggle-helper&quot;&gt;&lt;code&gt;ember-toggle-helper&lt;/code&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Pure-function helpers are simple to grok and understand, so a look at addons like &lt;a href=&quot;https://github.com/jmurphyau/ember-truth-helpers&quot;&gt;&lt;code&gt;ember-truth-helpers&lt;/code&gt;&lt;/a&gt; is sufficient to understand them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ember-route-action-helper&lt;/code&gt; uses the class based implementation, which must define a &lt;code&gt;compute&lt;/code&gt; method. This is then invoked every time one of the positional arguments to the helper changes. &lt;/p&gt;

&lt;p&gt;Under the hood, the &lt;code&gt;route-action&lt;/code&gt; helper retrieves the router from the application instance as a computed property, then locates the function reference from the currently active routes:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;getRouteWithAction&lt;/span&gt;(router, actionName) {
  let handler = emberArray(getRoutes(router)).find((route) =&amp;gt; {
    &lt;span class=&quot;comment&quot;&gt;// find the route with the action&lt;/span&gt;
  });

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; { action, handler };
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The action and the handler (route) is then returned, and wrapped with a closure action, which allows us to do all the nice stuff we expect from any other closure action in Ember. By returning a function in a helper, you can essentially &amp;quot;decorate&amp;quot; the action helper with some custom functionality.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;compute([actionName, ...params]) {
  let &lt;span class=&quot;function&quot;&gt;action&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(...invocationArgs) {
    let args = params.concat(invocationArgs);
    let { action, handler } = getRouteWithAction(router, actionName);

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; run.join(handler, action, ...args);
  };

  &lt;span class=&quot;comment&quot;&gt;// return the closure action&lt;/span&gt;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And because Helper classes are just like any other class in Ember, you can do the usual things like inject services, define computed properties, and so on. Here&amp;#39;s a contrived example:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  &lt;span class=&quot;key&quot;&gt;inject&lt;/span&gt;: { service },
  Helper,
  observer,
  get
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Helper.extend({
  &lt;span class=&quot;key&quot;&gt;session&lt;/span&gt;: service(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),

  compute([shoe]) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; parseInt(get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;session.currentUser.shoeSize&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)) === parseInt(get(shoe, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;));
  },

  &lt;span class=&quot;key&quot;&gt;onShoeSizeChange&lt;/span&gt;: observer(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;session.currentUser.shoeSize&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.recompute();
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The simplified Helper class was introduced in &lt;a href=&quot;http://emberjs.com/blog/2015/06/12/ember-1-13-0-released.html#toc_new-ember-js-helper-api&quot;&gt;&lt;code&gt;1.13&lt;/code&gt;&lt;/a&gt;, and are an excellent addition to Ember. In my next post, I&amp;#39;ll talk a little bit more about them and how we can use them to replace certain CPs.&lt;/p&gt;

&lt;p&gt;Until next time, thanks for reading!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Data: Worryless Model Defaults</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/12/defaults-in-ember" />
    <id>https://dockyard.com/blog/2016/02/12/defaults-in-ember</id>
    <category term="javascript" label="JavaScript"/><category term="best-practices" label="Best Practices"/><category term="ember" label="Ember.js"/>
    <published>2016-02-12 00:00:00</published>
    <updated>2016-09-14 14:36:43</updated>
    <author><name>Romina Vargas</name></author>
    <summary>Take some precaution when setting object and array defaults on Ember Data models</summary>
    <content type="html">&lt;p&gt;When working with Ember Data models, itâs common to want to set default values for
certain attributes. Setting a default value on a model is super easy and
you&amp;#39;ve probably done it countless times:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Model from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data/model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; attr from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data/attr&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Model.extend({
  &lt;span class=&quot;key&quot;&gt;isHungry&lt;/span&gt;: attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;defaultValue&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt; })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above syntax works flawlessly for &lt;code&gt;Boolean&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, and &lt;code&gt;Number&lt;/code&gt;
types. But what if you want to set defaults on an &lt;code&gt;Object&lt;/code&gt; or an
&lt;code&gt;Array&lt;/code&gt; type?&lt;/p&gt;

&lt;p&gt;Before answering that question, you should note that Ember Data does not
have out of the box support for &lt;code&gt;Object&lt;/code&gt; and &lt;code&gt;Array&lt;/code&gt; types. Well, kinda.
If you don&amp;#39;t specify a type as the first argument to &lt;code&gt;DS.attr&lt;/code&gt;, it just
means the value for that attribute will be untouched rather than coerced
to the matching JavaScript type. You can easily add a
&lt;a href=&quot;https://guides.emberjs.com/v2.3.0/models/defining-models/#toc_transforms&quot;&gt;transform&lt;/a&gt; for a custom type. &lt;em&gt;Your transform should provide
serialize and deserialize methods for proper processing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now to answer the above question, your first instinct might be to do the
following:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// app/models/person.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Model from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data/model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; attr from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data/attr&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Model.extend({
  &lt;span class=&quot;key&quot;&gt;favoriteThings&lt;/span&gt;: attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;defaultValue&lt;/span&gt;: {} })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here, every new record created with the &lt;code&gt;Person&lt;/code&gt; model would be expected to have a
&lt;code&gt;favoriteThings&lt;/code&gt; value of &lt;code&gt;{}&lt;/code&gt;, rather than &lt;code&gt;undefined&lt;/code&gt;. Which is correct, but
only until you begin setting content on that object. An Ember Data model extends
from &lt;code&gt;Ember.Object&lt;/code&gt;, meaning that arrays and objects will be shared among
all instances of that model. If you&amp;#39;re not too familiar with that concept,
check out this past Ember Best Practices &lt;a href=&quot;https://dockyard.com/blog/2015/09/18/ember-best-practices-avoid-leaking-state-into-factories&quot;&gt;blog post&lt;/a&gt; from Estelle!&lt;/p&gt;

&lt;p&gt;The result from setting a model attribute default to an empty object:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let foo = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.store.createRecord(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
get(foo, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;favoriteThings&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; {}&lt;/span&gt;
set(foo, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;favoriteThings.food&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pozole&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
get(foo, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;favoriteThings&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; { food: &#39;pozole&#39; }&lt;/span&gt;

let bar = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.store.createRecord(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
get(bar, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;favoriteThings&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; { food: &#39;pozole&#39; }&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Trolling at its finest. Bar doesn&amp;#39;t even know what &amp;quot;pozole&amp;quot; is. (By the way, if you&amp;#39;ve
never had Mexican &lt;a href=&quot;https://en.wikipedia.org/wiki/Pozole&quot;&gt;pozole&lt;/a&gt;, you&amp;#39;re missing out!)&lt;/p&gt;

&lt;p&gt;This quirky functionality isn&amp;#39;t particular to Ember, however. It all stems from
JavaScript itself; this also happens with POJOs:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; foo = { &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; };
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; bar = foo;

bar.name = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

console.log(bar); &lt;span class=&quot;comment&quot;&gt;// { name: &#39;bar&#39; }&lt;/span&gt;
console.log(foo); &lt;span class=&quot;comment&quot;&gt;// { name: &#39;bar&#39; }&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Lucky for us, Ember has made it easier to avoid this pitfall by deprecating the use of a
complex object as a default value for a model property. If you try to set an attribute with
a default value of type &lt;code&gt;&amp;quot;object&amp;quot;&lt;/code&gt;, you&amp;#39;ll see a warning message: &lt;code&gt;Non primitive
defaultValues are deprecated because they are shared between all instances. If you would
like to use a complex object as a default value please provide a function that returns the
complex object.&lt;/code&gt; This is your cue to undo.&lt;/p&gt;

&lt;h2&gt;A better, and often forgotten option&lt;/h2&gt;

&lt;p&gt;Don&amp;#39;t fret, because this issue is just a simple fix away. &lt;code&gt;defaultValue&lt;/code&gt; also accepts
a function. Hooray! Let&amp;#39;s modify our code to work as we would expect.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// app/models/person.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Model from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data/model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; attr from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data/attr&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Model.extend({
  &lt;span class=&quot;key&quot;&gt;favoriteThings&lt;/span&gt;: attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;defaultValue&lt;/span&gt;: () =&amp;gt; {} })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That&amp;#39;s it! This will ensure that every &lt;code&gt;favoriteThings&lt;/code&gt; attribute contains its own object
instance. Having the ability to pass in a function to &lt;code&gt;defaultValue&lt;/code&gt; can also
prove helpful if you would like to set custom defaults based on computed
properties, as well as other attributes of the same model.&lt;/p&gt;

&lt;p&gt;Hope this served as a sweet reminder, or as something new that you can leverage
in your projects from now on.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Why DockYard transitioned to PostCSS</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/11/transition-to-postcss" />
    <id>https://dockyard.com/blog/2016/02/11/transition-to-postcss</id>
    <category term="postcss" label="Postcss"/><category term="css" label="Css"/>
    <published>2016-02-11 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Cory Tanner</name></author>
    <summary>DockYardâs UX Development team thought process behind transitioning to PostCSS</summary>
    <content type="html">&lt;p&gt;The UX Development Team at DockYard takes pride in the ability to adapt to the latest tools that improve our workflow and benefit the team. We are always looking for tools that help with maintaining &lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;DRY&lt;/a&gt; CSS and quicken the development time of a projectâs CSS. Because of &lt;a href=&quot;https://github.com/postcss/postcss&quot;&gt;PostCSSâs&lt;/a&gt; evolving plugin library, PostCSS is the latest addition to our development process.&lt;/p&gt;

&lt;p&gt;PostCSS is the new &lt;a href=&quot;https://twitter.com/PostCSS/status/689886395763179522&quot;&gt;big kid on the block&lt;/a&gt; and for good reason. It has provided developers with modularity and flexibility in CSS development. The ability to add and remove plugins that fit a projectâs development process separates PostCSS from other tools that we used in the past.&lt;/p&gt;

&lt;h1&gt;What we used in the past&lt;/h1&gt;

&lt;p&gt;In the past we used Sass for all our projects and utilized the parts of Sass that we needed. Along with Sass we used a combination of &lt;a href=&quot;https://css-tricks.com/bem-101/&quot;&gt;BEM&lt;/a&gt; and &lt;a href=&quot;https://smacss.com/&quot;&gt;SMACSS&lt;/a&gt; for naming conventions and file structure based on DockYardâs styleguides.&lt;/p&gt;

&lt;p&gt;When we began using Autoprefixer, we had to lay it on top of Sass. This meant that we had to manage multiple tools, which increased setup time.&lt;/p&gt;

&lt;p&gt;We were using the best available tools within our workflow that we could at the time. As you know, it feels like a new development tool comes out every month. Over time, we felt we could improve the environment of how we were writing our CSS.&lt;/p&gt;

&lt;h1&gt;Introducing PostCSS&lt;/h1&gt;

&lt;p&gt;PostCSS provides us with the flexibility to adopt new plugins with ease and within one NPM package that we manage at DockYard.&lt;/p&gt;

&lt;p&gt;The PostCSS plugins we choose focus on two things. DRY CSS that does not trip over itself on overlapping styles, and creating organized CSS modules that have class names that explain themselves based on DockYardâs &lt;a href=&quot;https://github.com/DockYard/styleguides/tree/master/ux-dev&quot;&gt;styleguides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We want developers who see our project tomorrow (or in two years) not to be confused by our naming conventions.&lt;/p&gt;

&lt;p&gt;We use five PostCSS plugins in our projects. To get our projects up and running even easier, we combined them into a package called &lt;a href=&quot;https://github.com/dockyard/narwin-pack&quot;&gt;narwin-pack&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jonathantneal/postcss-partial-import&quot;&gt;postcss-partial-import&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/postcss/postcss-nested&quot;&gt;postcss-nested&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/postcss/postcss-custom-properties&quot;&gt;postcss-custom-properties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jonathantneal/postcss-svg-fragments&quot;&gt;postcss-svg-fragments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/postcss/autoprefixer&quot;&gt;autoprefixer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those five plugins allow us to have modular CSS and use simple variables to speed up our development time. We are able to choose plugins that meet our development needs with no extra âbells and whistlesâ. What makes PostCSS so appealing is the ability to easily add and remove plugins from our custom made package.&lt;/p&gt;

&lt;p&gt;We also have syntax rules that we follow while using these plugins - more on those in our next blog post going over each plugin in detail.&lt;/p&gt;
</content>
  </entry><entry>
    <title>How to have a side project</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/10/how-to-have-a-side-project" />
    <id>https://dockyard.com/blog/2016/02/10/how-to-have-a-side-project</id>
    <category term="design" label="Design"/><category term="creativity" label="Creativity"/><category term="culture" label="Culture"/><category term="inspiration" label="Inspiration"/><category term="team" label="Team"/><category term="art" label="Art"/>
    <published>2016-02-10 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Focus on one project at a time. Bonus: see what DockYarders do outside work!</summary>
    <content type="html">&lt;p&gt;Pretty much every designer I know has a side project (or five). They are often in a field related to design, but do not replicate exactly what they do at their full time job. Side projects and hobbies are great for relaxing, while adding extra skills or addressing a passion that does not yet have a place in one&amp;#39;s career.&lt;/p&gt;

&lt;p&gt;Hereâs what I learned about what works well, and what can be problematic for side projects Iâve had over the years. Hope it helps you in your own creative pursuit!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/5Tw9qYB.jpg&quot; alt=&quot;watercolor sketch with abstract shapes&quot;&gt;
&lt;em&gt;My watercolor sketch to study shapes and colors from Wassily Kandinsky&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;1: Different enough&lt;/h2&gt;

&lt;p&gt;To let your brain rest and relax, a side project should be different enough from what you do during the day. When a dayâs work is mostly at the computer, I feel a need to switch to analog afterwards, and still have lots of energy. If this is a &lt;a href=&quot;https://dockyard.com/design-sprints&quot;&gt;design sprint&lt;/a&gt; week, and Iâm on my feet most of the day, sketching or writing on the whiteboard - then curling up on my couch with a laptop feels like a welcome break. Essentially, I have different types of energy I could use up during the day, and switching between activities allows me to get more done.&lt;/p&gt;

&lt;p&gt;Another principle to keep in mind is to avoid conflicting interests between work and personal projects. When they are different enough, there is a clear separation between the two. I wonât resent filling my week-ends with the personal project, because it does not feel like work. It feels like play!&lt;/p&gt;

&lt;p&gt;Sports or dance make a great hobby &amp;amp; side project. I used to spend hours each week rock climbing, then switched to social dancing a few years later. It may seem like thereâs no overlap in the skills - but the ability to clearly lead and follow (typical Tango dance roles) within a larger group setting is a great communication skill for a team of designers as well. It also helped me learn my limitations. When youâre several rope-lengths up a cliff and need to tell something to other climbers on the team without seeing them, my voice never seemed loud enough to get across. Since then, I always think of a backup communication method. Do two tugs on the rope mean âgoâ? You only know if youâve arranged it ahead of time.&lt;/p&gt;

&lt;h2&gt;2: Similar enough&lt;/h2&gt;

&lt;p&gt;When work and play are in related disciplines, you get a lot of benefit in combining the two. For example, my photography hobby provided a ton of material for my design work - material that I owned and could art-direct myself. Hours of practicing lighting and portrait photography on the weekend allowed me to quickly organize consistent and flattering staff photos at work. Photography wasnât exactly in my job description, but it gave me better material to design the website.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/xekWIad.jpg&quot; alt=&quot;a friendly goat&quot;&gt;
&lt;em&gt;Photography is a hobby that often encourages me to get, and stay, outside&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;An active pursuit of two related disciplines can &lt;strong&gt;act as a multiplier&lt;/strong&gt;, where they feed off each other. Hobbies can âfeedâ on my primary work as well: I usually take time to design a logo and a few other pieces for each side project.&lt;/p&gt;

&lt;h2&gt;3: Frustrated? Pick just one&lt;/h2&gt;

&lt;p&gt;One problem with side projects is that they often compete for time with chores, rest and relaxation. And if I have too many side projects at the same time, the apparent lack of progress can be frustrating. At some point I remember I was doing a half-day photo shoot every other weekend (if you do photography, youâll know how much extra time it takes to sort and process the raw photos), had a pretty involved sewing project going (which takes both time and physical space), was learning French twice a week, and attempted to do a daily watercolor illustration. Oh, and a full time job with a lengthy commute.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/aReedp3.jpg&quot; alt=&quot;sewing project&quot;&gt;
&lt;em&gt;I miss sewing projects, but stopped doing them for the time being so I can focus on one thing at a time, with higher quality and time investment&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I would write an overly optimistic to-do list for my week-end, but only get about halfway through it. I was probably less effective at my day job than I could have been, due to lack of sleep. My side projects felt stagnant because there wasnât enough happening in each one from week to week. With these projects, the end goal was to produce a portfolio of creative work to apply to grad school. But I felt trapped because even with hard work, I wasnât making enough progress.&lt;/p&gt;

&lt;p&gt;I eventually climbed out of this. I negotiated Fridays off at work, trained the designer who would replace me, put together a portfolio and moved to Canada for a year to study. The experience left me with a better understanding of how important focus really is.&lt;/p&gt;

&lt;h2&gt;Focus&lt;/h2&gt;

&lt;p&gt;I now know I canât get good results from trying to juggle several side projects at a time. But deciding to do just one thing can feel scary. I often wonder if I&amp;#39;ll ever get to work on my other projects. But itâs the only sure way to make progress.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/kIUHUpm.jpg&quot; alt=&quot;Color blocks and sticky notes&quot;&gt;
&lt;em&gt;Johannes Ittenâs classic Elements of Color (the book belongs to both ym art life and my design life) and some sticky notes we use for UX design. The colors match perfectly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In 2015, I decided to focus on one side project: my exploration of the &lt;a href=&quot;http://www.designartpractice.com/&quot;&gt;overlap between design and modern art&lt;/a&gt;. I put away my sewing machines, and set my Etsy shop in holiday mode. I even stopped nagging myself to keep practicing with watercolors or hand lettering. I now have a more realistic to-do list, and can feel âdoneâ and accomplished with the weekly illustrated articles that I plan to write for a year.
Iâll be honest: I miss the other side projects I had put on hold. But I&amp;#39;m OK with not doing them for a while so that once I get to them, Iâll be able to make progress and commit to giving those other passions the focused time they deserve.&lt;/p&gt;

&lt;h2&gt;More examples!&lt;/h2&gt;

&lt;p&gt;I went around and asked my intimidatingly talented colleagues to share examples of what theyâre up to. Here they go!&lt;/p&gt;

&lt;h2&gt;Estelle&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Bqyq3ws.jpg&quot; alt=&quot;pencil portrait by Estelle&quot;&gt;
&lt;em&gt;Pencil Portrait from my very limited &lt;a href=&quot;https://www.behance.net/edeblois&quot;&gt;portfolio&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work?&lt;/strong&gt;
I tend to go back to the things I enjoyed doing before discovering the joy of programming. I have a variety of hobbies that I try to juggle as time permits, ranging from drawing or painting, practicing photography (I took an online photography course at the Photography Institute a few years ago and try to keep up), practicing piano (Iâve been taking weekly piano lessons for the past six years), and just gaming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
I donât particularly feel that any of those activities feed into my work at all, but itâs a nice distraction from my day-to-day work.&lt;/p&gt;

&lt;h2&gt;Brian&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/PCu2yYF.jpg&quot; alt=&quot;Elixir&quot;&gt;
&lt;em&gt;&lt;a href=&quot;http://elixir-lang.org/&quot;&gt;Elixir Language&lt;/a&gt; logo (image via &lt;a href=&quot;http://brunakochi.com/projects/elixir.html&quot;&gt;Bruna Kochi&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My after-hours time is spent on open source software. Right now I am working on Elixir tools that will be used to support our future application development efforts.&lt;/p&gt;

&lt;h2&gt;Steve&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Smaad8H.jpg&quot; alt=&quot;Black and white photo of hands&quot;&gt;
&lt;em&gt;A self portrait done on 35mm black and white film&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/odVVRMv.jpg&quot; alt=&quot;abstract photo of ice&quot;&gt;
&lt;em&gt;This is a picture I took of ice. Its appearance is more smokey than usual due to melting and refreezing, and because of the size of the river I took this in, I was able to capture somewhere around 15 original compositions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/BjGN6fP.jpg&quot; alt=&quot;Musical notation&quot;&gt;
This is purely representational for me of a possible musical composition. As I do not know how to write and read music, this serves as a visual for my work. Memory alone isnât enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
I compose and play music on various instruments. I also do photography.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
I think in any medium it is really important to let it express itself as much as I can allow it. I do not attempt to make them feed into each other. However, as I dive deeper into the creative process for each there is something, some way of thinking or structure, that Iâm able to carry back. For instance, I attempted to create 20 original songs in 12 hours, which sounds absolutely insane, but it is truly possible depending on how âbig pictureâ youâre willing to remain on the compositions. It really engrains the concept of taking broad strokes more seriously before getting caught in the details.&lt;/p&gt;

&lt;h2&gt;Amanda&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/5DITjtO.jpg&quot; alt=&quot;Portrait of a girl with eyes closed&quot;&gt;
&lt;em&gt;Oil and graphite on panel (18â x 24â)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
Prior to design and web development, my main passion was painting. During undergrad, I spent most of my time in the studio oil painting and I still do it occasionally. This painting was for the Fountain Art Fair in Chicago a couple years ago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
In UX development, I work closely with designers. Understanding basic design principles is useful. Many practices are transferrable like balance, contrast, composition and attention to detail. More abstractly, coding and painting come together quite similarly to me. Individual brush strokes or pencil lines form a hand or a pillow. In code combinations of letters and numbers make up shapes and components of a website.&lt;/p&gt;

&lt;h2&gt;Jon&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/QTHMjM5.jpg&quot; alt=&quot;Mountain biker in the woods&quot;&gt;
&lt;em&gt;2015 Pukwudgie Time Trial - Assonet, MA&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
Competitive mountain biking&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
Over the years I have participated in many team sports where the performance of the collective group dictates outcome of the competition.  Competitive mountain biking has taken out the variable of team and placed full responsibility on me.  Any success I have realized in this endeavor (which has been minimal to date) is a fringe benefit of deliberate training, sacrifice, failure and exhibition of mental toughness.  &lt;/p&gt;

&lt;p&gt;I love the fact teams are a significant part of my professional life - It is the only way I would want it to be.   However, outside of work I have chosen something that is âDifferent Enoughâ to keep my other lesser used mental and physical muscles engaged.&lt;/p&gt;

&lt;h2&gt;Lauren ï· paints!&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/2Scgp0F.jpg&quot; alt=&quot;Character sketch&quot;&gt;
&lt;img src=&quot;https://i.imgur.com/6jhegwr.jpg&quot; alt=&quot;Character sketch&quot;&gt;
&lt;img src=&quot;https://i.imgur.com/6e2Nq1G.jpg&quot; alt=&quot;Character sketch&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://i.imgur.com/a/RamRz#0&quot;&gt;Moar here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
Draw / paint characters and landscapes (usually from imagination, but sometimes from real life), but I havenât done it in a while and I miss it a lot. I want to buy a Wacom tablet again as my old one was left (sadly) in Australia.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
Art has taught me how to &lt;em&gt;see&lt;/em&gt; things, and my approach to painting has always been about improvisation. I usually work in digital, and I generally splash blocks of color and refine silhouettes that form into something coherent. I like to think of them as happy accidents that I can then go on and transform into something interesting.&lt;/p&gt;

&lt;p&gt;One of the best lessons Iâve taken away from art that translates well into programming is to pause occasionally, take a step back and evaluate the bigger picture before getting lost in the details. Composition is important, as is other elements like color, lighting, and brush stroke economy. Similarly, composing applications in the form of their architecture is also a process that requires much thought before a single line of code goes into the project.&lt;/p&gt;

&lt;h2&gt;Cory&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Wmq5T0U.jpg&quot; alt=&quot;Snowboarder sitting down on the slope&quot;&gt;
&lt;em&gt;Tremblant, Canada over winter break. Went for a week and stayed at a hostel and met amazing people&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/CpwlIgn.jpg&quot; alt=&quot;snowboard view&quot;&gt;
&lt;em&gt;Weekend trip up to Loon mountain for the first time. Big fan of exploring new mountains&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
Every year I attempt to plan out my winter snowboarding trips and look for new mountains I have not explored yet. I try to do at least one multi-day solo trip every year to absorb the entire experience differently than going with friends. Snowboarding for me is about connecting to nature and getting an adrenaline rush while pushing my limits as a snowboarder. The best day on a mountain for me is having no clouds in the sky, great music while riding, fluffy powder and empty slopes. Searching for that âunicornâ type of day is what keeps the excitement of going snowboarding fresh.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
I feel the constant exploration and creativity of snowboarding directly relates to UXD at DockYard. I am constantly trying to find new ways to build things and you have to be creative/think outside the box sometimes to come up with the best solution. Not only thinking outside the box but stepping outside your comfort zone is something I do with snowboarding and trying a new CSS technique. Taking a chance on something you are not sure you can do and just going for it has been something that has helped me as a developer and a snowboarder.&lt;/p&gt;

&lt;h2&gt;Marten&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/tcv5SiN.jpg&quot; alt=&quot;sweet potato appetizer&quot;&gt;
&lt;em&gt;Appetizer I made for Christmas dinner&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
In the weekends I like to go nuts on cooking. Weekdays I keep it simple.&lt;/p&gt;

&lt;p&gt;I also spend a lot of time in a local bar that has many different craft beers + drink craft beer at home.&lt;/p&gt;

&lt;h2&gt;Marin&lt;/h2&gt;

&lt;p&gt;Handmade bags:
&lt;img src=&quot;https://i.imgur.com/ZXHGU50.jpg&quot; alt=&quot;side project example&quot;&gt;
&lt;em&gt;(See &lt;a href=&quot;https://i.imgur.com/a/bTGuK&quot;&gt;more bag pics&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sculpture:
&lt;img src=&quot;https://i.imgur.com/1Pl6uad.jpg&quot; alt=&quot;sculpture outdoors&quot;&gt;
&lt;img src=&quot;https://i.imgur.com/fxUwznk.jpg&quot; alt=&quot;sculpture indoors&quot;&gt;&lt;/p&gt;

&lt;p&gt;Sketches:
&lt;img src=&quot;https://i.imgur.com/wKMw5r1.jpg&quot; alt=&quot;sketch&quot;&gt;
&lt;img src=&quot;https://i.imgur.com/8rOqtyT.jpg&quot; alt=&quot;sketch&quot;&gt;
&lt;img src=&quot;https://i.imgur.com/cfnq4Of.jpg&quot; alt=&quot;sketch&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
I make laptop cases, pencil cases and general purpose bags (pouches?) out of scrap fabric that I find or have. I also enjoy making sculptures out of various media, including metal, wire, or anything I can find (one time I used hundreds of marbles for a piece). And I like sketching people/faces using charcoal. Unfortunately, I donât have access to a big studio and lots of materials, so recently, I mostly stick with the bag making.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
In one sense I donât feel like my hobbies feed into my work very much. Which is nice because it&amp;#39;s a break from my day-to-day; getting to use my hands, and unwind. On the other hand, programming involves creativity and thinking outside of the box just like art.&lt;/p&gt;

&lt;h2&gt;Romina&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/5gJeZb8.jpg&quot; alt=&quot;runner&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
I enjoy cooking most nights of the week, I game, and I exercise. Fitness is my main focus, however.
Year-round (except winter), I run outside, otherwise I lean to miscellaneous fitness classes and gym equipment. I love racing and the competitive aspect of it; Iâve been running competitively since I was 11 years old. I strive to beat my previous times in races that I have previously ran. I just completed my first half marathon a few months back, which was a fun challenge. I love and hate the feeling when youâre about to start a race!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
I donât feel like my hobbies feed directly into my work, but they do play a role in my overall well-being since they serve as relaxation and a way to unwind from work and things life throws at me.&lt;/p&gt;

&lt;h2&gt;Tim&lt;/h2&gt;

&lt;p&gt;Mandala Project&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/LXtShBx.jpg&quot; alt=&quot;Mandala art&quot;&gt;
&lt;em&gt;After sketching, I arrived at the above digital renderings&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/hVzc2u6.jpg&quot; alt=&quot;Mandala on the side of a building&quot;&gt;
&lt;em&gt;The final result&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you do outside work&lt;/strong&gt;?
The images above are from a quick side project I worked on where I was commissioned to create and put up a mandala - a spiritual symbol representing the universe and often geometric in design. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you feel it feeds into your work, if at all&lt;/strong&gt;?
This was a huge learning process for me. Wheatpaste, a technique for applying artwork often associated to street art, was something I had never before attempted. This project allowed me to hone in on my digital design capabilities as well as practice a craft that requires more of a hands-on approach.&lt;/p&gt;

&lt;h2&gt;Patrick&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/NsN6tcv.jpg&quot; alt=&quot;Beer photo shoot&quot;&gt;
&lt;em&gt;2015 pumpkin beer bottle shoot light boxing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/SMNONrT.jpg&quot; alt=&quot;Beer&quot;&gt;
&lt;em&gt;Pumpkin beer and light photo experimentation&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/yUKe8tt.jpg&quot; alt=&quot;Beer&quot;&gt;
&lt;em&gt;Preliminary top downs of pumpkin beer pours for 2016 pumpkin beer photo mosaic&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Outside of work, I spend time tasting, photographing, and reviewing craft beer, particularly pumpkin beer. I run a pumpkin beer review site at &lt;a href=&quot;http://www.bumpinpumpkinbeer.com/&quot;&gt;bumpinpumpkinbeer.com&lt;/a&gt; where every year I taste close to 100 of the previous yearsâ best pumpkin beers. I curate photography experiments by doing so, as well as build archives of data on ingredient, recipe, and batch alterations, transitions, and successes which I enjoy visualizing. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/bf3f6un.jpg&quot; alt=&quot;beer&quot;&gt;
&lt;img src=&quot;https://i.imgur.com/ncFBGkd.jpg&quot; alt=&quot;beer&quot;&gt;
&lt;em&gt;Logo and color scheme for the Bumpinâ Pumpkin Beer review site&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I think this hobby has fed into my design work in that it has inspired me to pursue different avenues in design, and gain greater interest into parallel areas. For one, itâs constantly forcing me to write (reviewing means writing of course!) which in turn has made me feel more comfortable writing about design. It also has inspired me to pursue photography (out of need originally) and hand lettering (which is prominent in craft beer labeling and branding). Itâs constantly inspired me to pay closer attention to the immense complexity that goes into creating something seemingly so simple and beautiful. The grandeur of the craft, from years of testing recipes to the intricate labor of its packaging design, never ceases to impress me, especially since itâs a commodity thatâs taken for granted so often.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Self-reflecting Designer</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/10/the-self-reflecting-designer" />
    <id>https://dockyard.com/blog/2016/02/10/the-self-reflecting-designer</id>
    <category term="design-process" label="Design Process"/><category term="design" label="Design"/>
    <published>2016-02-10 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Patrick Branigan</name></author>
    <summary>Using self-reflection as a means to build character and confidence as a designer.</summary>
    <content type="html">&lt;p&gt;Meditation or serious thought about oneâs character, actions, and motives. This is the definition of self-reflection. &lt;/p&gt;

&lt;p&gt;Self-reflection is something a lot of designers donât consciously do enough of. Yet self-reflection is something designers 
take part in daily on behalf of other people. We are busy addressing other peopleâs needs, attempting to produce through 
other peopleâsâ eyes, and realizing other peopleâs thoughts and ideas, in pursuit of creating phenomenal products and 
services. This is what we love to do and sometimes we happen to be really good at it. However, weâre also users of our 
own products. We are the result of our own processes. Itâs worth spending time reflecting on our creative selves in order 
to continue to produce better for others. &lt;/p&gt;

&lt;p&gt;Being a designer whoâs able to self reflect comes with many benefits including the ability to be aware of progress, the 
ability to identify challenges, and the ability to become more observant.&lt;/p&gt;

&lt;p&gt;If designers take time to self reflect, they can intermittently check their work progress. Stepping back and looking at 
your work as an observer, not a designer, will often reveal sequences, patterns, and trends in progress. Perhaps you notice 
itâs taking longer than expected to produce a piece of work. Why is that? Perhaps you notice the redesign you did last year 
is similar to the one youâve just completed. Why is that? Perhaps you find that your process hasnât evolved, yet your work 
has. How is that possible? By surveying your work and reflecting upon it often, youâre likely to become more aware of 
progress and more cognizant of growth. &lt;/p&gt;

&lt;p&gt;Self-reflection can also help us in identifying challenging situations before they occur. We gain experience through the 
work weâve created, and often remember failures more than successes. Does this project meeting seem similar to a past 
conversation that went awry? What happened and how did you react? Perhaps a project brief scares you because it calls for 
a similar result to a project that once fell through. How did you handle that? What part did you play in its failure? 
Failure is an important part of the evolution of a designer and therefore should be reflected on in an effort to inform 
future decision-making and reasoning.&lt;/p&gt;

&lt;p&gt;Most importantly, self-reflection allows us to become more observant of ourselves when in motion. Observation produces 
curiosity and drives the imagination. However it also has the power to reveal negative tendencies and habits that have 
leaked into our processes over time. For example, you might find that youâre approaching the design of an application in 
the same way youâre approaching the design of a website. Is it because they both call for the same approach? Or is it 
because youâre subconsciously relying on the same approach due to its success in previous work? Trends and comfort are two 
aspects to design that, if you donât take time to question, can hinder experimentation and progress. Being able to better 
observe how youâre working while youâre working is beneficial to any designer.&lt;/p&gt;

&lt;p&gt;Youâd think self-reflection is easy, but itâs not. Itâs hard to find the time. Itâs hard to be honest with oneself. Itâs 
hard to occasionally focus on yourself in an industry where youâre constantly focused on the actions and reactions of 
consumers and peers.&lt;/p&gt;

&lt;p&gt;Hereâs a couple ways to help begin injecting self-reflection into your life as a designer:&lt;/p&gt;

&lt;h2&gt;Meet People&lt;/h2&gt;

&lt;p&gt;Surround yourself with friends and peers from other disciplines as often as you can. This will consistently provide 
perspective and insight into spaces and ideas you otherwise might be blind to in your everyday routine. It may allow for 
insight into your work that you might not have otherwise experienced.&lt;/p&gt;

&lt;h2&gt;Write Often&lt;/h2&gt;

&lt;p&gt;The rhythm and pace of writing your thoughts out, regardless of what they are, may in fact help you retain and further 
digest what youâre trying to express. It also allows you to reflect on your thoughts later on. &lt;/p&gt;

&lt;h2&gt;Extend Your Workspace&lt;/h2&gt;

&lt;p&gt;Work in spaces that are foreign to your everyday routine. A new space may influence both your thought process and work ethic. 
This presents the potential to make you question your routine and habits, therefore emphasizing self-reflection. Perhaps 
consider a sabbatical even.&lt;/p&gt;

&lt;h2&gt;Keep Your Books&lt;/h2&gt;

&lt;p&gt;If you take physical notes or have sketchbooks, archive them somewhere. Store them in a manageable place, in an organized 
way that allows for you to reference content from specific years or projects past. This allows for very easy self-reflection 
that will help you better understand what you have and have not accomplished in your journey as a creative. Itâs motivating 
at the very least.&lt;/p&gt;

&lt;p&gt;Iâve found the most beneficial quality of self-reflection to be its ability to provide a valuable perspective on your 
creative self. It forces consideration of what youâve accomplished, as well as how far youâve come. This helps in 
identifying future pursuits.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Pens, Paper, Scissors</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/05/pens-paper-scissors" />
    <id>https://dockyard.com/blog/2016/02/05/pens-paper-scissors</id>
    <category term="design-process" label="Design Process"/><category term="design" label="Design"/>
    <published>2016-02-05 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Patrick Branigan</name></author>
    <summary>Reintroducing materials into a web design process.</summary>
    <content type="html">&lt;p&gt;I was recently involved in a staff augmentation project with one other DockYarder. The project involved us working at
our clientâs office for approximately three months. Aside from a shift in daily culture and a completely different perspective on the projectâs challenges, I did discover a couple very, very simple techniques
Iâll be exploring further in the future.&lt;/p&gt;

&lt;p&gt;While my fellow DockYarder was tasked with user interface work for an existing application build, my task was to research,
conceptualize, and design a full fledged careers section of a website. This website is the marketing tool for a greater
web service. Itâs aimed at new users and represents the breadth of what the service and its suite of tools and programs
has to offer. What it failed to provide was a way for the client to recruit and entice prospective employees, which they would need in order to fill an immense amount of positions that were opening up in multiple locations.&lt;/p&gt;

&lt;p&gt;A lot of my time on this project was spent in research and brainstorming concepts, which meant a lot of data harvesting
and sketching. The results, prior to executing visual design, came in the form of Content Frames (a term I&amp;#39;ll explain in a later post). Using qualitative and quantitative research, we were able to quickly determine a viable layout
and hierarchy option for the careers section. We did this without any content having been developed by the client. In fact,
there was zero content at this point! Backwards sounding? Perhaps to some. Thatâs not what Iâm going to discuss though.
Instead I want to note just two simple techniques that made a strong impact on how the team communicated, and eventually on
how we were able to begin prototyping without content.&lt;/p&gt;

&lt;h2&gt;Sketch with ink&lt;/h2&gt;

&lt;p&gt;The first technique is to use ink when sketching. I use a set of Micron pens for various design tasks away from the screen. Iâve recently begun sketching all of my lower fidelity wireframes with them. Why? Because drawing out my wireframes is a therapeutic process. It allows me time to further think about what Iâm executing in the moment.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/hwHiUis.jpg&quot; alt=&quot;Pens&quot;&gt;&lt;/p&gt;

&lt;p&gt;The varying weights also allow me to quickly suggest element context (buttons are a thicker 0.8mm line while images are 0.5 for example). Also because ink is permanent. This challenges my mind to make more calculated decisions in what Iâm sketching and it disallows my cautious self to throw away or erase ideas that I put on paper. You never know how valuable a seemingly wrong idea might be later on.&lt;/p&gt;

&lt;h2&gt;Construct with paper, scissors, and tape&lt;/h2&gt;

&lt;p&gt;The second technique is utilizing the sketches to determine the content flow.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/KZDG5Qu.jpg&quot; alt=&quot;Dot grid paper&quot;&gt;&lt;/p&gt;

&lt;p&gt;Instead of limiting my sketches to the size of the dot grid paper (or any boundary for that matter) I sketched the page as
I saw it in its full length, running on to a new piece of paper when needed. At the end I simply taped them together. The
results were full page sketches that allowed the client to see the content holistically and sequentially, rather than parsed in a series of sketchbook pages, or having to continuously scroll multiple artboards on screen.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Zz6oaHw.jpg&quot; alt=&quot;Scissors&quot;&gt;&lt;/p&gt;

&lt;p&gt;If you have multiple concept sketches for the page, like I did, use scissors to cut and paste your conceptsâ components together. Do this with the client. In fact, have the client do the cutting and taping. It emphasizes involvement, provides the client a sense of authority, and allows for the entire team to immediately rearrange, reorganize or compile their feedback and ideas by cutting and retaping components to one another. After just one meeting, we were left with a new page concept. It was derived from, and composed of, components from two of the four concept sketches we started with.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/StONm4D.jpg&quot; alt=&quot;Tape&quot;&gt;&lt;/p&gt;

&lt;p&gt;Thereâs something refreshing about incorporating materials into an approach. Everyone felt more connected, more involved,
and frankly more confident with the work as we progressed. Granted the circumstances and constraints of my particular
situation allowed for me to experiment with my process in this way. But Iâd argue itâs always worth considering alternative
routes in the creative process when the situation allows for it.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Brace Expansion for Computed Properties</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/05/ember-practices-property-brace-expansion" />
    <id>https://dockyard.com/blog/2016/02/05/ember-practices-property-brace-expansion</id>
    <category term="ember" label="Ember.js"/><category term="best-practices" label="Best Practices"/><category term="javascript" label="JavaScript"/>
    <published>2016-02-05 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Doug Yun</name></author>
    <summary>DRYing up computed properties since 2014</summary>
    <content type="html">&lt;p&gt;As an Ember developer, I can count on fresh features popping up almost every
other month within a new release. There are numerous benefits to this, which
certainly are out of the scope of this blog post. However, I will briefly
cover one particular gem from 2014 - an oldie, but goodie - of a feature.&lt;/p&gt;

&lt;p&gt;How many times have you written something like this?&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  Component,
  computed,
  get
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;key&quot;&gt;farmSentence&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;animal.species&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;animal.noise&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;farmer.name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;farmer.location&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      let animal = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      let farmer = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;farmer&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;At &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(farmer, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)}, Farmer &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(farmer, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)} owns a &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(animal, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;species&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)} that says &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;${get(animal, &#39;noise&#39;)}!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
    }
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice how we consume &lt;code&gt;animal.species&lt;/code&gt;, &lt;code&gt;animal.noise&lt;/code&gt;, &lt;code&gt;farmer.name&lt;/code&gt;, and &lt;code&gt;farmer.location&lt;/code&gt;?
There are a lot of &lt;em&gt;shared&lt;/em&gt; dependent keys. Gross.&lt;/p&gt;

&lt;h2&gt;Computed Property Brace Expansion&lt;/h2&gt;

&lt;p&gt;Well, &lt;a href=&quot;http://emberjs.com/blog/2014/02/12/ember-1-4-0-and-ember-1-5-0-beta-released.html#toc_property-brace-expansion)&quot;&gt;back in 2014, &amp;quot;brace expansion&amp;quot; was introduced&lt;/a&gt;.
Let&amp;#39;s use this feature and tidy up our component!&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  Component,
  computed,
  get
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;key&quot;&gt;farmSentence&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;animal.{species,noise}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;farmer.{name,location}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      let animal = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      let farmer = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;farmer&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;At &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(farmer, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)}, Farmer &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(farmer, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)} owns a &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(animal, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;species&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)} that says &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;${get(animal, &#39;noise&#39;)}!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
    }
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Why use Brace Expansion?&lt;/h2&gt;

&lt;p&gt;Isn&amp;#39;t that much nicer? I prefer using brace expansion, because it &lt;strong&gt;organizes&lt;/strong&gt; the dependent keys and
makes it &lt;strong&gt;easier to read&lt;/strong&gt;. Goodness forbid a coworker of yours writes dependent keys without ordering
them alphabetically:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;...

&lt;span class=&quot;comment&quot;&gt;// This ordering isn&#39;t ideal&lt;/span&gt;
farmSentence: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;animal.noise&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;farmer.name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;animal.species&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;farmer.location&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  get() {
    let animal = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;animal&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    let farmer = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;farmer&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;At &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(farmer, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)}, Farmer &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(farmer, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)} owns a &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{get(animal, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;species&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)} that says &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;${get(animal, &#39;noise&#39;)}!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
  }
})

...
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To those new to Ember, hope you learned something new!
And to those experienced in Ember, hope this was a refresher!
And to my coworkers that don&amp;#39;t use brace expansions, shame on you!&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Setting up revision previews with Ember CLI Deploy</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/03/ember-cli-deploy-revision-previews" />
    <id>https://dockyard.com/blog/2016/02/03/ember-cli-deploy-revision-previews</id>
    <category term="ember" label="Ember.js"/>
    <published>2016-02-03 00:00:00</published>
    <updated>2016-03-24 15:25:16</updated>
    <author><name>Marten Schilstra</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I recently set up previewing revisions with &lt;a href=&quot;http://ember-cli.com/ember-cli-deploy/&quot;&gt;Ember CLI Deploy&lt;/a&gt;.
There is no single best practice on how to do this yet, but here is how I did
it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post assumes you use the
&lt;a href=&quot;https://github.com/ember-cli-deploy/ember-cli-deploy-revision-data&quot;&gt;ember-cli-deploy-revision-data&lt;/a&gt; plugin in
conjunction with an index adapter (&lt;a href=&quot;https://github.com/ember-cli-deploy/ember-cli-deploy-redis&quot;&gt;Redis&lt;/a&gt;, &lt;a href=&quot;https://github.com/ember-cli-deploy/ember-cli-deploy-s3-index&quot;&gt;S3&lt;/a&gt;,
&lt;a href=&quot;https://github.com/green-arrow/ember-cli-deploy-ssh-index#readmehttps://github.com/green-arrow/ember-cli-deploy-ssh-index#readme&quot;&gt;SSH&lt;/a&gt;) for Ember CLI Deploy.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;About revisions&lt;/h3&gt;

&lt;p&gt;Everytime you deploy &lt;code&gt;index.html&lt;/code&gt; with Ember CLI deploy, it gets tagged with a
revision. By default this is an MD5 hash of the &lt;code&gt;index.html&lt;/code&gt; file itself, but it
can also be a Git commit hash, or the version from your &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;How exactly &lt;code&gt;index.html&lt;/code&gt; gets tagged depends on the index adapter. For example:
using the S3 adapter, the tag will be appended to the filename; using Redis, the
tag will be part of the key where the file is stored.&lt;/p&gt;

&lt;p&gt;Once you have one or more revisions deployed to the target server, you can
activate one of the revisions, which will be the default &lt;code&gt;index.html&lt;/code&gt;
the users of your app will see.&lt;/p&gt;

&lt;h3&gt;Viewing revisions without having to activate them&lt;/h3&gt;

&lt;p&gt;It would be very nice to be able preview a revision (maybe QA test) on the
production server, before you activate it and release it to the public. My idea
was to be able to do this by visiting
&lt;code&gt;https://example.com/rev-a76df687f97e9ab8ca82d1a1/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is really simple to set up your webserver to do this, so I won&amp;#39;t go into
that, but there is a caveat on the Ember side of this. If you navigate to the
revision, the router will throw an error: &lt;code&gt;The route rev-a76df687f97e9ab8ca82d1a1/
was not found&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What is happening? The &lt;code&gt;Ember.Router&lt;/code&gt; is not intelligent enough to know that you
meant to route after the &lt;code&gt;/rev-a76df687f97e9ab8ca82d1a1/&lt;/code&gt; portion of the path.&lt;/p&gt;

&lt;p&gt;You have to explicitly configure the router to route on a path other than &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Fixing the router&lt;/h3&gt;

&lt;p&gt;Setting up the router to work from a base path should be fairly straightforward,
for example to route on &lt;code&gt;/awesome-app/&lt;/code&gt; you can set the
&lt;a href=&quot;http://emberjs.com/api/classes/Ember.Router.html#property_rootURL&quot;&gt;&lt;code&gt;rootUrl&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { Router } = Ember;

const Router = Router.extend({
  &lt;span class=&quot;key&quot;&gt;location&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;rootURL&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To route revisions is a little more complex, as you can&amp;#39;t just type in a simple
string and be done with it. To be able to handle revisions, you can make the
&lt;code&gt;rootURL&lt;/code&gt; a computed property instead:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  Router,
  computed,
  isPresent
} = Ember;

const Router = Router.extend({
  &lt;span class=&quot;key&quot;&gt;location&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

  &lt;span class=&quot;key&quot;&gt;rootURL&lt;/span&gt;: computed(() =&amp;gt; {
    let path = window.location.pathname;

    &lt;span class=&quot;comment&quot;&gt;// Looks for /rev-a76df687f97e9ab8ca82d1a1/ at the beginning of the path&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// Tweak this regex to match your own style of revisions.&lt;/span&gt;
    let revisionMatch = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; RegExp(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;^/(rev-[^/]+)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).exec(path);

    &lt;span class=&quot;comment&quot;&gt;// If there was a revision at the beginning of the path&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// return it as rootURL&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (revisionMatch &amp;amp;&amp;amp; isPresent(revisionMatch[&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;])) {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;${revisionMatch[1]}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
    } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
    }
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When the application loads, the &lt;code&gt;rootURL&lt;/code&gt; computed property will be executed once.
If the &lt;code&gt;rev-*&lt;/code&gt; part is in the path it will return that as the &lt;code&gt;rootURL&lt;/code&gt;, else it
will just return the default &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Caveat: baseURL is set in ENV&lt;/h3&gt;

&lt;p&gt;By default the &lt;code&gt;baseURL&lt;/code&gt; property in your &lt;code&gt;config/environment.js&lt;/code&gt; is &lt;code&gt;/&lt;/code&gt; and
does not interfere with the &lt;code&gt;rootURL&lt;/code&gt; in the router, but when it is something
like &lt;code&gt;/awesome-app&lt;/code&gt;, then you will run into trouble.&lt;/p&gt;

&lt;p&gt;It is best to not use &lt;code&gt;baseURL&lt;/code&gt; in conjunction with &lt;code&gt;rootURL&lt;/code&gt;. If you have a base
path the app is served from, I would recommend you add it to the &lt;code&gt;rootURL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is how I solved it:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; config from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;./config/environment&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  Router,
  computed,
  isPresent
} = Ember;

const Router = Router.extend({
  &lt;span class=&quot;key&quot;&gt;location&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

  &lt;span class=&quot;key&quot;&gt;rootURL&lt;/span&gt;: computed(() =&amp;gt; {
    let baseRootURL = config.baseRootURL || &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;comment&quot;&gt;// NOTE: This is not baseURL&lt;/span&gt;
    let path = window.location.pathname;

    let revisionMatch = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; RegExp(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;^&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{baseRootURL}/(rev-[^&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;])`).exec(path);

    if (revisionMatch &amp;amp;&amp;amp; isPresent(revisionMatch[1])) {
      return `${baseRootURL}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{revisionMatch[&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;]}/&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
    } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{baseRootURL}/&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;;
    }
  })
});
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;So now you know&lt;/h3&gt;

&lt;p&gt;If you have a backend that serves revisions on a scheme like
&lt;code&gt;/rev-a76df687f97e9ab8ca82d1a1/&lt;/code&gt;, then this is one way to set up your Ember app
to work with that scheme. Don&amp;#39;t forget to check your app&amp;#39;s &lt;code&gt;baseUrl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you figured out another way to set up something like this, then please share
it!&lt;/p&gt;
</content>
  </entry><entry>
    <title>How to contribute to Elixir</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/02/how-to-contribute-to-elixir" />
    <id>https://dockyard.com/blog/2016/02/02/how-to-contribute-to-elixir</id>
    <category term="elixir" label="Elixir"/>
    <published>2016-02-02 00:00:00</published>
    <updated>2016-03-24 15:25:16</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I just got my &lt;a href=&quot;https://github.com/elixir-lang/elixir/pull/4233&quot;&gt;first commit accepted into the Elixir programming
language&lt;/a&gt;. Here are some notes on how to build and test &lt;a href=&quot;http://elixir-lang.org&quot;&gt;Elixir&lt;/a&gt; on your
machine to help you make your own contributions.&lt;/p&gt;

&lt;h3&gt;Up and running&lt;/h3&gt;

&lt;p&gt;After you&amp;#39;ve &lt;a href=&quot;https://github.com/elixir-lang/elixir&quot;&gt;cloned Elixir&lt;/a&gt; you&amp;#39;ll need to ensure that the state of your
copy builds properly and all the tests pass. To do this you&amp;#39;ll need to
use &lt;a href=&quot;https://en.wikipedia.org/wiki/Make_(software)&quot;&gt;Make&lt;/a&gt;. Simply run the following:&lt;/p&gt;
&lt;div class=&quot;highlight console &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ make compile
$ make test
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Hopefully the purpose of each command should be obvious. The entire test suite for
the language doesn&amp;#39;t take too long to complete. Once all the tests pass
you can start. In the event that any of the two steps fail I would
recommend getting help in the &lt;code&gt;#elixir-lang&lt;/code&gt; IRC channel on Freenode.&lt;/p&gt;

&lt;h3&gt;You&amp;#39;ve made your changes&lt;/h3&gt;

&lt;p&gt;Assuming you&amp;#39;ve made your changes you&amp;#39;ll need to test them. For any
changes that you&amp;#39;ve made to the language you&amp;#39;ll need to recompile. You
can re-run the commands from above in the root directory of the project.&lt;/p&gt;

&lt;p&gt;Elixir itself is made up of several packages. They&amp;#39;re all listed in the
&lt;code&gt;lib/&lt;/code&gt; directory:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;lib
âââ eex
âââ elixir
âââ ex_unit
âââ iex
âââ logger
âââ mix
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Depending upon the package you are making changes to you may not want to
run the entire test suite. For example, to compile and run the tests for
&lt;code&gt;ex_unit&lt;/code&gt; only you can run:&lt;/p&gt;
&lt;div class=&quot;highlight console &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ make test_ex_unit
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/elixir-lang/elixir/blob/d9748b4e3139fbac98119aa8ee697af06c40b0ec/Makefile#L206&quot;&gt;Check out the &lt;code&gt;Makefile&lt;/code&gt; in Elixir for the available commands for testing 
individual packages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even this can be tedious. If you really want to move fast you can target
a specific test file to run. Let&amp;#39;s say you want to target the test file
for &lt;code&gt;ExUnit.Case&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight console &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ make compile
$ bin/elixir -r lib/ex_unit/test/test_helper.exs lib/ex_unit/test/ex_unit/case_test.exs
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The second command will use the custom build of Elixir that is the
result from &lt;code&gt;make compile&lt;/code&gt;. The option &lt;code&gt;-r&lt;/code&gt; will run the specific
file at that path.&lt;/p&gt;

&lt;p&gt;This should get you into a faster feed-back loop to ensure that your
tests for the changes you&amp;#39;ve made are passing.&lt;/p&gt;

&lt;h3&gt;Real-world testing&lt;/h3&gt;

&lt;p&gt;It could be that you are making a commit to scratch an itch in an app
you&amp;#39;re building. In that event it would be great to ensure that the
changes you&amp;#39;re making in the language actually work for you. We can
easily test this by using the custom build of Elxiir with your
application.&lt;/p&gt;

&lt;p&gt;In a Linux-based shell you can prepend the &lt;code&gt;bin/&lt;/code&gt; path of the custom
Elixir build onto &lt;code&gt;$PATH&lt;/code&gt; so it takes precedence:&lt;/p&gt;
&lt;div class=&quot;highlight console &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ export PATH=/home/yourname/elixir/bin:$PATH
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Replace &lt;code&gt;/home/yourname/elixir/bin&lt;/code&gt; with whatever the path is for your
machine. If you really want to live on the edge you can add this to your
&lt;a href=&quot;https://en.wikipedia.org/wiki/Bash_(Unix_shell)&quot;&gt;Bash&lt;/a&gt; or &lt;a href=&quot;http://www.zsh.org/&quot;&gt;Zsh&lt;/a&gt; config, but I wouldn&amp;#39;t recommend it.&lt;/p&gt;

&lt;p&gt;You should confirm that your custom build is the one found. You can do
this by running: &lt;code&gt;which elixir&lt;/code&gt; and &lt;code&gt;which mix&lt;/code&gt;. If it doesn&amp;#39;t return
the path for the custom build you should revisit the steps above and see
why not.&lt;/p&gt;

&lt;p&gt;You will likely need to recompile the dependencies for the custom build
of Elixir:&lt;/p&gt;
&lt;div class=&quot;highlight console &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ mix do deps.clean, deps.get, deps.install
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Assume your application is using the changes you&amp;#39;ve made just run &lt;code&gt;mix
test&lt;/code&gt; as normal to confirm that your changes work.&lt;/p&gt;

&lt;h3&gt;Documentation&lt;/h3&gt;

&lt;p&gt;You may have to document your changes. &lt;a href=&quot;http://elixir-lang.org/docs/master/elixir/writing-documentation.html&quot;&gt;Please see the Elixir guide on
writing good documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Bad builds&lt;/h3&gt;

&lt;p&gt;Sometimes there may be a bad build during compilation. In this event you
can just run:&lt;/p&gt;
&lt;div class=&quot;highlight console &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ make clean
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This will reset the project to a clean state. You can now try to
re-compile.&lt;/p&gt;

&lt;h3&gt;Finish up&lt;/h3&gt;

&lt;p&gt;I think you&amp;#39;ll be surprised how easy and straight forward it is to
contribute back to Elixir. Hopefully these tips have made it a bit
smoother for you.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Elixir Best Practices - Deeply Nested Maps</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/02/01/elixir-best-practices-deeply-nested-maps" />
    <id>https://dockyard.com/blog/2016/02/01/elixir-best-practices-deeply-nested-maps</id>
    <category term="best-practices" label="Best Practices"/><category term="elixir" label="Elixir"/>
    <published>2016-02-01 00:00:00</published>
    <updated>2016-03-24 15:25:16</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;When writing Elixir apps you&amp;#39;ll typically find yourself building up
state in a &lt;a href=&quot;http://elixir-lang.org/getting-started/keywords-and-maps.html&quot;&gt;map&lt;/a&gt;. Typically these maps contain deep 
nesting. Updating anything deeply nested means you have to write something like:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_map = %{
  foo: %{
    bar: %{
      baz: &amp;quot;my value&amp;quot;
    }
  }
}

new_bar_map =
  my_map
  |&amp;gt; Map.get(:foo)
  |&amp;gt; Map.get(:bar)
  |&amp;gt; Map.put(:baz, &amp;quot;new value&amp;quot;)

new_foo_map =
  my_map
  |&amp;gt; Map.get(:foo)
  |&amp;gt; Map.put(:bar, new_bar_map)

Map.put(my_map, :foo, new_foo_map)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That&amp;#39;s pretty complex for a simple nested key update!
Elixir has a better way: &lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Kernel.html#put_in/3&quot;&gt;&lt;code&gt;Kernel.put_in/3&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This function uses the &lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Access.html&quot;&gt;Access&lt;/a&gt; &amp;quot;behaviour&amp;quot; to drastically
reduce the keystrokes for inserting into deeply nested maps. Let&amp;#39;s take
a look at refactoring the above example:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_map = %{
  foo: %{
    bar: %{
      baz: &amp;quot;my value&amp;quot;
    }
  }
}

put_in(my_map, [:foo, :bar, :baz], &amp;quot;new value&amp;quot;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That&amp;#39;s it! The really nice thing about this function is that the 2nd
argument is simply a list which means when we&amp;#39;re dealing building
complex maps during recursion we can simply append to the list.&lt;/p&gt;

&lt;p&gt;Similarly, we can get deeply nested values in a map using
&lt;code&gt;Kernel.get_in/2&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_map = %{
  foo: %{
    bar: %{
      baz: &amp;quot;my value&amp;quot;
    }
  }
}

get_in(my_map, [:foo, :bar, :baz]) == &amp;quot;my value&amp;quot;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s go deeper. Does the list syntax feel like too many characters to
you? Let me introduce you to &lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Kernel.html#put_in/2&quot;&gt;&lt;code&gt;Kernel.put_in/2&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;put_in(my_map.foo.bar.baz, &amp;quot;new value&amp;quot;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This version of the function is a &lt;a href=&quot;https://github.com/elixir-lang/elixir/blob/v1.2.2/lib/elixir/lib/kernel.ex#L1831-L1839&quot;&gt;macro that will break up the syntax
and deal with each part of the path individually&lt;/a&gt;. It may feel like
magic but it&amp;#39;s just Elixir doing what it does best: blowing your mind.&lt;/p&gt;

&lt;p&gt;Still going deeper...&lt;/p&gt;

&lt;p&gt;Now its time to get fancy. Let&amp;#39;s say you want to update the values
according to a function. To do that we&amp;#39;ll use
&lt;a href=&quot;http://elixir-lang.org/docs/stable/elixir/Kernel.html#update_in/3&quot;&gt;&lt;code&gt;Kernel.update_in/3&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_map = %{
  bob: %{
    age: 36
  }
}

update_in(my_map, [:bob, :age], &amp;amp;(&amp;amp;1 + 1))
#=&amp;gt; %{bob: %{age: 37}}

update_in(my_map.bob.age, &amp;amp;(&amp;amp;1 + 1))
#=&amp;gt; %{bob: %{age: 37}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Dealing with Lists and Structs&lt;/h3&gt;

&lt;p&gt;Deeply nested lists can also make use of these functions. However, there
is a difference in the short-hand syntax.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_list = [foo: [bar: [baz: &amp;quot;my value&amp;quot;]]]

put_in(my_list[:foo][:bar][:baz], &amp;quot;new value&amp;quot;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is referred to as &amp;quot;&lt;a href=&quot;https://github.com/elixir-lang/elixir/blob/v1.2.2/lib/elixir/lib/access.ex#L50&quot;&gt;field-based lookup&lt;/a&gt;&amp;quot; and can
differ depending upon the type you are acting upon. Maps can work with
either form:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_map[:foo][:bar][:baz]
#=&amp;gt; &amp;quot;my value&amp;quot;

my_map.foo.bar.baz
#=&amp;gt; &amp;quot;my value&amp;quot;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Lists only work with the bracket form:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_list[:foo][:bar][:baz]
#=&amp;gt; &amp;quot;my value&amp;quot;

my_list.foo.bar.baz
#=&amp;gt; ** (ArgumentError) argument error
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Structs only work with the path form:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_struct.foo.bar.baz
#=&amp;gt; &amp;quot;my value&amp;quot;

my_struct[:foo][:bar][:baz]
#=&amp;gt;  ** (UndefinedFunctionError) undefined function MyStruct.fetch/2
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I hope this helps you deal with deeply nested maps, lists, and structs!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Running Elixir and Phoenix projects on a cluster of nodes</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/01/28/running-elixir-and-phoenix-projects-on-a-cluster-of-nodes" />
    <id>https://dockyard.com/blog/2016/01/28/running-elixir-and-phoenix-projects-on-a-cluster-of-nodes</id>
    <category term="deployment" label="Deployment"/><category term="elixir" label="Elixir"/><category term="phoenix" label="Phoenix"/>
    <published>2016-01-28 00:00:00</published>
    <updated>2016-08-10 21:43:18</updated>
    <author><name>Chris McCord</name></author>
    <summary>How to use distributed elixir in a few simple steps</summary>
    <content type="html">&lt;p&gt;Once you&amp;#39;re ready to deploy your Elixir application to multiple servers, you&amp;#39;ll want to take advantage of the distributed features that the runtime offers. For example, if you are using Phoenix channels, you&amp;#39;ll want broadcasts to be sent across the cluster. You can setup your deployment as a cluster in a few simple steps:&lt;/p&gt;

&lt;p&gt;Start by creating a new &lt;code&gt;sys.config&lt;/code&gt; file in your project. We&amp;#39;ll conventionally use the name &lt;code&gt;sys.config&lt;/code&gt; because Erlang assumes exactly one system configuration file is used when building releases, with this name. Add the following contents the new file:&lt;/p&gt;
&lt;div class=&quot;highlight erlang &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;[{kernel,
  [
    {sync_nodes_optional, [&#39;n1@127.0.0.1&#39;, &#39;n2@127.0.0.1&#39;]},
    {sync_nodes_timeout, 10000}
  ]}
].
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this example, we have two nodes in the cluster, &lt;code&gt;n1@127.0.0.1&lt;/code&gt; and &lt;code&gt;n2@127.0.0.1&lt;/code&gt;. The &lt;code&gt;sync_nodes_optional&lt;/code&gt; configuration specifies which nodes to attempt to connect to within the &lt;code&gt;sync_nodes_timeout&lt;/code&gt; window, before continuing with startup. There is also a &lt;code&gt;sync_nodes_mandatory&lt;/code&gt; key which can be used to enforce all nodes are connected within the timeout window or else the node terminates. With our &lt;code&gt;sys.config&lt;/code&gt; in place, we can pass a VM &lt;code&gt;-config&lt;/code&gt; flag to use our configuration when booting the Erlang VM. For example, you could start two iex sessions like this:&lt;/p&gt;
&lt;div class=&quot;highlight console &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;n1@host$ iex --name n1@127.0.0.1 --erl &amp;quot;-config sys.config&amp;quot; -S mix
n2@host$ iex --name n2@127.0.0.1 --erl &amp;quot;-config sys.config&amp;quot; -S mix
iex(n2@127.0.0.1)1&amp;gt; Node.list
[:&amp;quot;n1@127.0.0.1&amp;quot;]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you&amp;#39;re building Phoenix projects, you could start your servers like this:&lt;/p&gt;
&lt;div class=&quot;highlight console &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;n1@host$ elixir --name n1@127.0.0.1 --erl &amp;quot;-config sys.config&amp;quot; -S mix phoenix.server
n2@host$ elixir --name n2@127.0.0.1 --erl &amp;quot;-config sys.config&amp;quot; -S mix phoenix.server
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You might be wondering why we have to use Erlang-based configuration in our &lt;code&gt;sys.config&lt;/code&gt; instead of Mix configuration. This is because the configuration must be passed to the Erlang VM when starting. By the time Mix configuration would be loaded, the VM has already booted. That said, we can use Mix configuration to drive our &lt;code&gt;sync_nodes_optional&lt;/code&gt; list if we are using &lt;a href=&quot;https://github.com/bitwalker/exrm&quot;&gt;exrm&lt;/a&gt; to build releases for deployment. &lt;code&gt;exrm&lt;/code&gt; builds your Mix configuration into a &lt;code&gt;sys.config&lt;/code&gt; within the release, which lets you specify your node configuration like this, in your Mix config:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;config :kernel,
  sync_nodes_optional: [:&amp;quot;n1@127.0.0.1&amp;quot;, :&amp;quot;n2@127.0.0.1&amp;quot;],
  sync_nodes_timeout: 10000
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then you build and run your releases as normal and the proper VM configuration is provided when starting. For a complete rundown on using &lt;code&gt;exrm&lt;/code&gt; to deploy a Phoenix project, see the &lt;a href=&quot;http://www.phoenixframework.org/docs/advanced-deployment&quot;&gt;official guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That&amp;#39;s all it takes to run distributed Elixir on a cluster of servers! The Erlang VM supports a number of more advanced options and strategies for running distributed applications, including automatic application failover to a configured subset of nodes, and more. See the &lt;a href=&quot;http://erlang.org/doc/design_principles/distributed_applications.html&quot;&gt;Erlang documentation&lt;/a&gt; for a comprehensive rundown.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Home away from home</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/01/22/home-away-from-home" />
    <id>https://dockyard.com/blog/2016/01/22/home-away-from-home</id>
    <category term="community" label="Community"/><category term="culture" label="Culture"/><category term="team" label="Team"/>
    <published>2016-01-22 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Ashley Treni</name></author>
    <summary>A short reflection</summary>
    <content type="html">&lt;p&gt;For those who donât know my journey with DockYard, itâs quite an amazing story. &lt;/p&gt;

&lt;p&gt;As an imposingly curious grad student studying data visualization, I absolutely couldnât resist the urge to jump into a conversation I overheard while bartending at Highball Lounge in March of 2014 (who can resist buzzwords like &amp;quot;information architecture&amp;quot;, &amp;quot;JavaScript&amp;quot;, and &amp;quot;data&amp;quot;!). A nice chat and a short introduction later, I was invited by Brian and Dan of DockYard to reach out and learn more about the company. I was immediately intrigued - both by the conversation and also the type of people who didnât dismiss me because of my job (as most tend to do to those who work in the service industry).&lt;/p&gt;

&lt;p&gt;Iâll never forget the first conversation I had with Steve when I went to the DockYard office to learn about the design team. I was absolutely amazed that they would consider me for an internship, and saw value in my curiosity and engagement, rather than the checklist of my industry experience (which, for the record, was non-existent). After a summer internship in 2014 where I was welcomed with open arms and &lt;a href=&quot;https://dockyard.com/blog/2014/07/18/design-as-conversation&quot;&gt;jumped right into the conversation&lt;/a&gt;, I joined DockYard full time in January 2015. This was during my final semester of grad school, and I received a tremendous amount of support from my colleagues while I worked simultaneously on my &lt;a href=&quot;http://www.designtaxonomy.com/#/standardimprovisations/&quot;&gt;Masterâs thesis project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few weeks later, I moved to Brooklyn for summer 2015. I saw an opportunity to bridge two worlds that were very important to me - DockYardâs consulting services and civic technology. I asked for permission to take a leave of absence to attend a fellowship at &lt;a href=&quot;http://labs.robinhood.org/&quot;&gt;Blue Ridge Labs&lt;/a&gt;, a social impact incubator focused on problem solving with technology for low income communities in New York. It was an amazing thing to receive their blessing and support.&lt;/p&gt;

&lt;p&gt;DockYard is an amazing place that values people and relationships. But I think the most incredible part, which Iâve been so fortunate enough to receive time and again, is the grace of its individuals&amp;#39; willingness to mentor and teach. While some companies are in search of unicorns and are in the game of stealing resources, DockYard seeks out something special in its employees more important than skill, and fosters the growth of individual people as well as talent. &lt;/p&gt;

&lt;p&gt;Today is bittersweet, because it is my last day at DockYard, and in the city of Boston. What Iâve been lucky to find I will be taking with me - the awareness to pay attention to qualities rather than attributes, to share and to be open, and to prioritize heart, sincerity, drive, and curiosity above all else.&lt;/p&gt;

&lt;p&gt;DockYard is truly special (and youâd be hard pressed to find a &lt;a href=&quot;https://medium.com/@sugarpirate/warning-breaking-changes-afeb2544d0f5#.ata8oqafn&quot;&gt;DockYarder&lt;/a&gt; who doesnât feel this way). I feel proud and quite blessed to say that DockYard is my home away from home. Iâd like to take this opportunity to thank my friends, colleagues, and mentor, Steve, at DockYard; it&amp;#39;s been an absolute privilege to learn and grow in this community with all of your support.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Heroic Elixir Pipelines</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/01/22/heroic-elixir-pipelines" />
    <id>https://dockyard.com/blog/2016/01/22/heroic-elixir-pipelines</id>
    <category term="elixir" label="Elixir"/><category term="best-practices" label="Best Practices"/>
    <published>2016-01-22 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Aaron Sikes</name></author>
    <summary>The pipe operator has a huge effect on Elixir for how simple it is. Learn how to use its power in your own functions</summary>
    <content type="html">&lt;p&gt;One small source of beauty in Elixir code is the &lt;a href=&quot;http://elixir-lang.org/docs/v1.0/elixir/Kernel.html#%7C%3E/2&quot;&gt;pipe operator&lt;/a&gt;. It passes the expression on the left as the first argument to the function on the right:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;1..100_000
|&amp;gt; Enum.map(&amp;amp;(&amp;amp;1 * 3))
|&amp;gt; Enum.filter(odd?)
|&amp;gt; Enum.sum
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here, a range of numbers is being passed through a chain of several operations. Much of the Elixir standard library can be used like this.&lt;/p&gt;

&lt;p&gt;Code like this is great to read. Itâs got a protagonist. Our hero navigates trials, and comes out changed on the other side. Humans are wired to understand a story.&lt;/p&gt;

&lt;p&gt;But do you ever think about how to keep your own functions pipeable? Hereâs a hypothetical bit of Elixir code:Â &lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def read_time(str) do
  str
  |&amp;gt; String.split(&amp;quot; &amp;quot;)
  |&amp;gt; Enum.count
  |&amp;gt; Kernel./(200)
  |&amp;gt; Integer.to_string
  |&amp;gt; Kernel.&amp;lt;&amp;gt;(&amp;quot;minutes&amp;quot;)
end

def related_posts(title, body) do
  related_posts_by_title(title) ++ related_posts_by_body_text(body)
end

...

def publish_post(%Post{body: body, title: title} = post) do
  word_count = read_time(body)
  related_posts = related_posts(title, body)
  App.publish(%{post | word_count: word_count, related_posts: related_posts})
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here, the wonderful piping action is present in the &lt;code&gt;read_time&lt;/code&gt; function, where youâre sticking to the standard library. But where did it go in the &lt;code&gt;publish_post&lt;/code&gt; method? The functions you&amp;#39;re writing aren&amp;#39;t built to facilitate piping. A good pipeable function takes some thought.&lt;/p&gt;

&lt;p&gt;Who is your hero? Here it&amp;#39;s your &lt;code&gt;post&lt;/code&gt; object. To write pipeable functions, your functions should take this hero as their first argument, and return a modified version/representation. Your first argument is your pipe intake, and your return value is your pipe outflow.&lt;/p&gt;

&lt;p&gt;Taking your hero as your second argument (as the sidekick), or taking only specific properties, or returning another value rather than a modified version can all break pipeability. Sometimes you want to do those things for unit tests, or for encapsulation and reusability, but you can always write a wrapping function that is more pipeable. Hereâs how Iâd use those techniques here:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def annotate_read_time(%Post{} = post) do
  %{post | read_time: read_time(post.body)}
end

def add_related_posts(%Post{body: body, title: title} = post) do
  %{post | related_posts: related_posts(body, title)}
end

...

def publish_post(%Post{} = post) do
  post
  |&amp;gt; annotate_read_time()
  |&amp;gt; add_related_posts()
  |&amp;gt; App.publish()
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Ah, thatâs better! We realized our hero is the humble post. It learns a few things about itself along the way, and at the end of its journey is published to the world.&lt;/p&gt;

&lt;p&gt;So. When writing your code, discover your protagonist. Write functions which take your hero as the first argument, and return it changed for the better. Then The Heroâs Journey will be complete, and you can have beautiful pipelines running all throughout your code.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Phoenix best practice: Decorating in views</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/01/15/phoenix-best-practice-decorating-in-views" />
    <id>https://dockyard.com/blog/2016/01/15/phoenix-best-practice-decorating-in-views</id>
    <category term="best-practices" label="Best Practices"/><category term="phoenix" label="Phoenix"/><category term="elixir" label="Elixir"/>
    <published>2016-01-15 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Dan McClain</name></author>
    <summary>Keeping your logic where it belongs</summary>
    <content type="html">&lt;p&gt;Recently I was updating an older Phoenix app that was built when I was
first familiarizing myself with Phoenix and realized there were a couple
architectural mistakes in some of the controllers and views. I rectified
those mistakes with the following patterns.&lt;/p&gt;

&lt;h2&gt;Keep your database out of my view by preloading&lt;/h2&gt;

&lt;p&gt;The view layer in Phoenix serves as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Decorator_pattern&quot;&gt;decorator&lt;/a&gt; for
the template you are about to render. It serves to merge data retrieved
in the controller with the additional details that may be needed. On our
&lt;a href=&quot;http://jsonapi.org/&quot;&gt;JSON API&lt;/a&gt; backends, we use &lt;a href=&quot;https://github.com/AgilionApps/ja_serializer&quot;&gt;ja_serializer&lt;/a&gt; to
convert our models into the proper response. When we have additional
details (say we include a blog post&amp;#39;s author for side loading into
Ember), we  want to make sure that we preload this data before it gets
to the view. If we preload from the view itself, we will be creating an
&lt;a href=&quot;http://stackoverflow.com/a/97253&quot;&gt;N+1 scenario&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s take the case of an index route where you have 20 posts you want
to render. When we wait until we get to the view&amp;#39;s &lt;code&gt;show.json&lt;/code&gt; (which
renders the individual post) to retrieve the author, we will be doing 20
additional SQL queries, as we will be getting the post one by one. If we
preload the author relationship in the controller, we will be executing
a single query that retrieves &lt;em&gt;all&lt;/em&gt; the authors and places them in the
struct with the post information.&lt;/p&gt;

&lt;h2&gt;Keep your decoration out of your controllers&lt;/h2&gt;

&lt;p&gt;You may have additional information you want your view to have access
to. In one case that I came across, we query the database to find the
number of blog posts a specific tag has. We end up storing the
information in a map in the function we created to look up that
information, where the key is the id of the tag, and the value is the
number of posts for that tag. We just went over why you don&amp;#39;t want to do
this work in your view, so how do we pass that information down? We can
use the &lt;code&gt;Plug.Conn.assign&lt;/code&gt; (&lt;a href=&quot;http://hexdocs.pm/plug/Plug.Conn.html#assign/3&quot;&gt;docs&lt;/a&gt;) to store the
information on the &lt;code&gt;conn&lt;/code&gt; which is passed to render in the controller.
What we don&amp;#39;t want to do is start &lt;code&gt;Enum.map&lt;/code&gt;ing across the list of tags
and munging the data in the controller. That would be &lt;em&gt;decorating&lt;/em&gt; the
model, which is the job of the view.&lt;/p&gt;

&lt;h2&gt;Everything in its right place&lt;/h2&gt;

&lt;p&gt;By following the practice of decorating in the view, and doing data
retrieval in the controller, it actually makes it quite difficult to
create an N+1 query. When you have a list of records, the easiest way to
preload data (if you aren&amp;#39;t using &lt;code&gt;Ecto.Query.preload&lt;/code&gt;), is to call
&lt;code&gt;Repo.preload(collection, keys)&lt;/code&gt;, which will only perform a single query
in the end.&lt;/p&gt;

&lt;p&gt;Moving from Rails to Phoenix, I&amp;#39;ve personally found there to be fewer
footguns to shoot myself with. I think a big part of that ends up being
the fact that with a functional language, you can&amp;#39;t accidentally make a
call to the database because your relationship can&amp;#39;t load itself. With
Ecto, I have to explicitly load the data for the relationships and that
requires me to think about &lt;em&gt;when&lt;/em&gt; is the best point to do so.&lt;/p&gt;
</content>
  </entry><entry>
    <title>This business needs to be about more than just business</title>
    <link rel="alternate" href="https://dockyard.com/blog/2016/01/05/this-business-needs-to-be-about-more-than-just-business" />
    <id>https://dockyard.com/blog/2016/01/05/this-business-needs-to-be-about-more-than-just-business</id>
    <category term="opinion" label="Opinion"/><category term="business" label="Business"/>
    <published>2016-01-05 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I just fired a client. Day one in the year.&lt;/p&gt;

&lt;p&gt;I&amp;#39;ve done it before, I&amp;#39;ll likely do it again. This one hurt. We&amp;#39;ve
worked with this client for the past eight months to rebuild their
platform. I&amp;#39;ve given them breaks on price. I&amp;#39;ve given them free
engineering time. In the end it came down to a lack of respect for the
relationship they had.&lt;/p&gt;

&lt;p&gt;Each year I&amp;#39;ve written a retrospective about how the year went, the ups
and downs of running a consultacy. In the first retrospective I wrote:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dockyard.com/blog/opinion/2012/06/21/lessons-learned-six-month-of-running-dockyard&quot;&gt;&lt;em&gt;&amp;quot;As a consultancy we are looking to make money by engaging clients. If
anybody tells you they&amp;#39;re consulting because it is their passion or work
with startups, they are full of shit.&amp;quot;&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can tell you right now that I was full of shit. I got into consulting
&amp;quot;for the money&amp;quot; but over the past four years we&amp;#39;ve built a company that
has grown to 23 people. We&amp;#39;ve followed our passions with technology and
design. We&amp;#39;ve made major contributions back to and have financially
supported the software projects we think are going to build the web for
the next decade and beyond. We made mistakes and we&amp;#39;ve made incredible
bets that have paid off.&lt;/p&gt;

&lt;p&gt;One of our engineers recently told me a story about how he was hanging
out with a friend of his girlfriend. That friend knew our engineer was in
software but didn&amp;#39;t know the name of the company. The friend began to speak
about how he was reading a series of blog posts on Ember.js. That blog
was our blog and that friend was impressed when our engineer told the friend
where he worked.&lt;/p&gt;

&lt;p&gt;This was actually an incredible moment for me when I
heard this story. This was the first time that I heard a story about
someone knowing about DockYard without our prompting them. Perhaps this
may seem pedantic to you. But knowing that we&amp;#39;ve built something that
people know about and respect has become very important to me.&lt;/p&gt;

&lt;p&gt;I realize that I&amp;#39;m emotionally wrapped up in DockYard. Arguably to the
point where it may impact my efficacy as CEO. Today I
fired a client because of the lack of respect they showed to us as
people. Is this good business? I don&amp;#39;t know, probably not. But I&amp;#39;ve become convinced
that this business needs to be about more than just business.&lt;/p&gt;
</content>
  </entry><entry>
    <title>How to uncover hidden assumptions</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/12/22/how-to-uncover-hidden-assumptions" />
    <id>https://dockyard.com/blog/2015/12/22/how-to-uncover-hidden-assumptions</id>
    <category term="planning" label="Planning"/><category term="design" label="Design"/><category term="business" label="Business"/><category term="design-process" label="Design Process"/>
    <published>2015-12-22 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Spend the time to talk about assumptions upfront. You&#39;ll save effort and frustration on any project.</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/lemN7lE.jpg&quot; alt=&quot;Invisible Assumptions&quot;&gt;&lt;/p&gt;

&lt;h2&gt;A 911 fail&lt;/h2&gt;

&lt;p&gt;The first time I had ever called 911 was for an almost non-emergency reason. Driving on an Interstate highway through Baltimore, we noticed a large ladder that had fallen off a construction truck. It was blocking two lanes out of four, and cars were veering to the side to avoid it. &lt;/p&gt;

&lt;p&gt;Because we were one of the first ones to notice the ladder falling off, and I was a passenger, I was in a good place to call and report debris on the road. So I called 911, assuming theyâd quickly route my call to the department that can easily deal with this stuff.&lt;/p&gt;

&lt;p&gt;The call went something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hello, Iâd like to report a dangerous situation on the road.&lt;/li&gt;
&lt;li&gt;Ok, where are you?&lt;/li&gt;
&lt;li&gt;Iâm on Route 95, between exits 51 and 52, heading North, there is dangerous debris on the roadâ¦&lt;/li&gt;
&lt;li&gt;Are you in the city or the county?&lt;/li&gt;
&lt;li&gt;â¦&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After a few attempts back and forth, I couldnât answer the dispatcherâs question because I didnât know where the city / county border was. It was certainly not on my phoneâs map apps. We were still driving, so I no longer was at the exact location.  I was also getting frustrated because the dispatcher did not seem to care for my attempts to give her a location by highway exit number, or by listing the streets the highway crossed near the area. After a few minutes I gave up and the report went nowhere.&lt;/p&gt;

&lt;h2&gt;Perspectives and assumptions&lt;/h2&gt;

&lt;p&gt;I can only assume the dispatcherâs role was to route my call to the next responsible party. For her, the agency in charge of traffic safety in the city, and the other agency in charge of the county are completely different things. For me, and anyone on the ground, the difference between those territories could be invisible. The border is not marked, and could lie across two corners of the same intersection. In general, the public wonât usually see these boundaries in the same way administrators do.&lt;/p&gt;

&lt;p&gt;However, the dispatcher had responded to my call with the assumption that anyone calling 911 locally would know if they are âin the city or the countyâ. Her assumption and my assumption did not match, and an emergency call failed as a result.&lt;/p&gt;

&lt;p&gt;I disagree with that assumption: even though I lived in the Baltimore area for four years, Iâd only know the city/county border location for the immediate neighborhood where I lived. Even then, it was only because the university I attended had famously lobbied to move that border so they could have a more prestigious Baltimore city address. I wouldnât expect a typical 911 caller to know this stuff.&lt;/p&gt;

&lt;p&gt;I donât fault the dispatcher in this case, by the way. Even though she could have been more prepared to understand my perspective, I can see how her environment could have made the city / county distinction so obvious it became an invisible assumption.&lt;/p&gt;

&lt;h2&gt;A designerâs job is to find out&lt;/h2&gt;

&lt;p&gt;It is important to discover the assumptions built in to a project. This responsibility is shared, but designers are often in the best position to lead this discovery because we deal both with understanding a userâs needs and the tools we might use to implement a solution. &lt;/p&gt;

&lt;p&gt;Part of this discovery process is requirements gathering: we understand and document the business goals the client aims to achieve, the restrictions that will inform the choice of design tools and technologies, and the user and industry insights that will inform the functionality can propose for an application.&lt;/p&gt;

&lt;p&gt;But in addition to gathering requirements, we must discover the âobviousâ things to people close to the product. These assumptions are so self-evident to the person who holds them that they wonât likely be included with requirements, or even communicated voluntarily. Designers must ask the âobviousâ questions to uncover those things and continue asking them throughout the process. &lt;/p&gt;

&lt;p&gt;Not communicating those assumptions makes a project ripe for surprises. If you donât talk about the obvious things, everyone can hold on to conflicting assumptions for a long time. Making changes to address hidden assumptions after a portion of the work has been done adds cost (and frustration!) and decreases efficiency.&lt;/p&gt;

&lt;h2&gt;How to uncover hidden assumptions&lt;/h2&gt;

&lt;p&gt;To uncover hidden assumptions, designers must ensure open and frequent communication. It may feel like over-communicating at first, but will start to feel natural with practice. Here are a few of the practices we use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Daily updates&lt;/strong&gt;
On most projects, we update the client on our progress daily. While it may seem like a chore to write up an additional description after the dayâs work has been completed, the updates force us to communicate clearly and often. This gives the client an opportunity to correct our assumptions early in the process.&lt;/p&gt;

&lt;p&gt;These updates can include questions (e.g. âHow many people are likely to experience this particular use-case?â) and assumptions we need confirmed (e.g. âWe have found that most users will leave this setting untouched, so we included this default value. Is this value a safe one to default to?â). Pro tip: request feedback from a client with a clear list of questions and assumptions they can quickly confirm or correct. This format makes it easier for the client to respond, so itâs more likely that youâll quickly get the information you need to move forward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flow diagrams&lt;/strong&gt;
We often produce flow diagrams to map out the universe around the product weâre building. When all team members have access to a visual representation of the entire product, and things that influence it, we often find problems and special cases that were not previously considered.&lt;/p&gt;

&lt;p&gt;Flow diagrams often include elements like triggers (what caused a process to be started), decision points (yes / no), variables (including an approximate range) and tentative bits (we are explicitly marking some part of the process as outside the scope, or as a secondary requirement).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Annotated wireframes and sketches&lt;/strong&gt;
We always annotate wireframes and sketches. We may draw low-fidelity sketches at first, but will note the type of content that might be included in a specific screen, and the reasoning and user goals that informed a specific layout. Notes like this will help frame the follow-up discussion with the client.&lt;/p&gt;

&lt;h2&gt;TL; DR&lt;/h2&gt;

&lt;p&gt;A difference in expectations is one of the most preventable causes of projects going wrong. And among all expectations, assumptions can be the most dangerous: they feel so âobviousâ that we donât even bring them up. If even a 911 call can be derailed by a dispatcherâs assumption, so can a large collaborative project. &lt;/p&gt;

&lt;p&gt;And just like in the 911 call, itâs possible to prevent misunderstanding by asking the âobviousâ questions. The dispatcher could have asked for my location in a different way - by street intersection, or exit number. And if her standard process did not include the assumption that a caller would know where the border between the City and the County lies, she would have been able to route me successfully by asking the question in a different form.&lt;/p&gt;

&lt;p&gt;Donât be that 911 dispatcher. Spend the time to &lt;a href=&quot;https://dockyard.com/blog/2014/07/18/design-as-conversation&quot;&gt;talk about assumptions up front&lt;/a&gt; - and youâll save everyone on the team time, effort, and unnecessary frustration.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Which diagrams when?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/12/21/which-diagrams-when" />
    <id>https://dockyard.com/blog/2015/12/21/which-diagrams-when</id>
    <category term="information-graphics" label="Information Graphics"/><category term="discovery" label="Discovery"/><category term="design-strategy" label="Design Strategy"/><category term="best-practices" label="Best Practices"/>
    <published>2015-12-21 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Ashley Treni</name></author>
    <summary>Design best practices - utilizing diagrams</summary>
    <content type="html">&lt;p&gt;Diagrams are incredibly valuable as methods of communication. Through visual language and spatial representation, diagrams give form to concepts and ideas.&lt;/p&gt;

&lt;p&gt;Diagram: (definition) &lt;em&gt;a simplified drawing showing the appearance, structure, or workings of something; a schematic representation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Mental model: (definition) &lt;em&gt;an explanation of someone&amp;#39;s thought process about how something works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At DockYard, we use various diagrams at different stages of the design process. Each type documents and captures different aspects of the design research process. It is valuable to know when in the process these diagrams can be used, as they can support conversations between different stakeholders and help to align understanding.&lt;/p&gt;

&lt;p&gt;The following case study utilizes a few of the diagrams we used here at DockYard. Each of these examples highlights the type of diagram and when in the design process they should be used. (We use &lt;a href=&quot;https://www.omnigroup.com/omnigraffle&quot;&gt;OmniGraffle&lt;/a&gt; to build these diagrams.)&lt;/p&gt;

&lt;h3&gt;Case Study: OutdoorKidz.com&lt;/h3&gt;

&lt;p&gt;OurdoorKidz.com (fictional!) is a new online store that specializes in seasonal outdoor gear and activites for kids. We&amp;#39;ve been hired to design and build the customer facing website, which houses the entire inventory of products and allows customers to purchase gear directly from the website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Target User:&lt;/strong&gt; Parents with young kids who are looking for outdoor gear and activities for kids.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Design and build an online store that allows target audience to search for, compare, and purchase items.&lt;/p&gt;

&lt;h4&gt;1. Journey Map - Design Research&lt;/h4&gt;

&lt;p&gt;A journey map is diagram in the form of a timeline, which identifies a userâs arrival to and experience surrounding the use of the product. Journey maps are often developed from a user persona based on the target user. They help to understand the context in which someone might interact with the product: why they seek it out, where they interact with it, and what they hope to gain from it. Understanding the use case informs design decisions early on, framing the major actions the user might want to take (features) within the product flow.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/3ZNISil.png&quot; alt=&quot;Journey Map&quot;&gt;
&lt;a href=&quot;https://www.dropbox.com/s/rr1tik21er82bva/Journey_Map.pdf?dl=0&quot;&gt;Journey Map PDF&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;2. User Flow - Product Development&lt;/h4&gt;

&lt;p&gt;A user flow is a diagram of the high level product experience, used to frame the actions taken within the product itself. They are generated from the use case (journey map), allowing us to break down the step by step interactions that must take place for the user to accomplish their goal.&lt;/p&gt;

&lt;p&gt;User flows become the basis for sketching and wireframing major areas of the interface. The navigation, framed around the user experience, informs the information architecture and interface design. Through wireframing, actual content is placed in context and functionalities are incorporated to support calls to action.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/qlLEcAd.png&quot; alt=&quot;User Flow&quot;&gt;
&lt;a href=&quot;https://www.dropbox.com/s/rd4diyfpteogplo/User%20Flow.pdf?dl=0&quot;&gt;User Flow PDF&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;3. Master Product Flow - Product Development&lt;/h4&gt;

&lt;p&gt;When we build complex interfaces, they often have multiple use cases. This master user flow connects the customer facing interface, OutdoorKidz.com online store, to the inventory management system for the employees of OutdoorKidz.com. The products overlap where orders come in and invetory is tracked. Connecting the two separate user flows can show the points where the two systems overlap. This can help to ensure the systems are built efficiently and speak to one another.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/L9jx16u.png&quot; alt=&quot;Product Flow&quot;&gt;
&lt;a href=&quot;https://www.dropbox.com/s/8g3onvpoqevyllj/Master%20Flow.pdf?dl=0&quot;&gt;Product Flow PDF&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Knowing when and how to incorporate these diagrams can be very valuable to your process. Diagrams are also good for documentation and tracking decisions throughout the process. They support discussion around problem solving, and can clarify that all stakeholders in the conversation share a common understanding of the solution.&lt;/p&gt;

&lt;p&gt;Here are some of my favorite resources about diagrams and mental models.&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.101designmethods.com&quot;&gt;101 Design Methods&lt;/a&gt; - Vjay Kumar&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.amazon.com/100-Diagrams-That-Changed-World/dp/0452298776&quot;&gt;100 Diagrams that Changed the World&lt;/a&gt; - Scott Christianson&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.dubberly.com/models&quot;&gt;Models of Design&lt;/a&gt; - Hugh Dubberly&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Service Backed Components</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/12/07/best-practices-service-backed-components" />
    <id>https://dockyard.com/blog/2015/12/07/best-practices-service-backed-components</id>
    <category term="javascript" label="JavaScript"/><category term="best-practices" label="Best Practices"/><category term="ember" label="Ember.js"/>
    <published>2015-12-07 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Embrace one-way data flow and get your app ready for routable components.</summary>
    <content type="html">&lt;p&gt;At EmberConf 2015, &lt;a href=&quot;https://twitter.com/wycats&quot;&gt;Yehuda Katz&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/tomdale&quot;&gt;Tom Dale&lt;/a&gt; announced the arrival of certain changes to Ember 2. Most notably, the &lt;a href=&quot;https://github.com/emberjs/rfcs/pull/38&quot;&gt;routable components RFC&lt;/a&gt; attracted a lot of attention because of its proposal to deprecate and eventually remove controllers. Naturally, this was alarming to many existing Ember users, especially since Ember and Sproutcore have always been MVC frameworks. &lt;/p&gt;

&lt;h2&gt;Goodbye MVC&lt;/h2&gt;

&lt;p&gt;It is no secret that many new Ember 2 conventions and changes have direct influence from &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt; and &lt;a href=&quot;https://facebook.github.io/flux/docs/overview.html#content&quot;&gt;Flux&lt;/a&gt; (a pattern for data flow in React apps). What Flux calls the &amp;quot;unidirectional data flow&amp;quot; is what we call &amp;quot;Data down, actions up&amp;quot; (DDAU) in Ember. &lt;/p&gt;

&lt;p&gt;DDAU avoids the traditional MVC pattern in favor of a single flow of data (hence unidirectional), which makes apps easier to reason about, and improves their performance. The fundamental problem with MVC is revealed as your application grows larger and more complex â cascading updates and implicit dependencies lead to a tangled mess and unpredictability. Updating one object leads to another changing, which in turn triggers more changes, and ultimately makes maintaining your application a frustrating experience.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/A6gg5zA.png&quot; alt=&quot;Data down, actions up&quot;&gt;&lt;/p&gt;

&lt;p&gt;In the DDAU pattern, data flows one-way and there are no two-way bindings. Different parts of your application can remain highly decoupled and predictable, which means you will always know the source of an object&amp;#39;s change. If you&amp;#39;ve read my post on &lt;a href=&quot;https://dockyard.com/blog/2015/11/16/best-practices-functional-programming-and-the-observer-effect&quot;&gt;functional programming and the observer effect&lt;/a&gt;, you&amp;#39;ll understand why it&amp;#39;s important to keep your components free from side effects.&lt;/p&gt;

&lt;p&gt;Instead of spending time cobbling together your own makeshift framework with a dozen micro-libraries and bike-shedding on the best way to implement a feature, using Ember means instant productivity and quick developer on-boarding. Combined with the DDAU pattern and the Glimmer rendering engine, Ember developers have both productivity and performance out of the box. &lt;/p&gt;

&lt;h2&gt;Preparing your application for DDAU&lt;/h2&gt;

&lt;p&gt;When routable components land, controllers will be deprecated and removed. Controllers and views have always been confusing for new Ember users, and &amp;quot;80% of their use cases were to do something that was fundamentally a component&amp;quot; (watch Yehuda and Tom explain more in this &lt;a href=&quot;https://www.youtube.com/watch?v=QgycDZjOnIg&quot;&gt;video&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Since Ember components aren&amp;#39;t singletons, they will be torn down and re-rendered in an optimized fashion when Glimmer deems necessary. How then to handle state persistence when controllers go away? &lt;/p&gt;

&lt;p&gt;For example, you might have some property on your controller that holds on to state that you would like to preserve throughout the app. To do so in Ember 2 (and today), we can remove that controller property in favor of &amp;quot;service-backed components&amp;quot;. The service will hold on to singleton component state, and explicitly injected only where necessary. Because services are powerful and can be easily abused, I&amp;#39;ll talk more about it at the end of this post.&lt;/p&gt;

&lt;h2&gt;Implementing service backed components&lt;/h2&gt;

&lt;p&gt;In the following example, I&amp;#39;ll demonstrate how you can use services and one-way bindings today. You can follow along below as well as check out the &lt;a href=&quot;https://poteto.github.io/component-best-practices/#/service-backed&quot;&gt;demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our little application consists of a couple of checkboxes for selecting animals. This selection needs to persist across different routes, and restore state when returning back to the route. All we need is to define a simple service that holds state for the selected items, and then inject it into the routable component.&lt;/p&gt;

&lt;p&gt;In the route&amp;#39;s template, we can just render the injected service&amp;#39;s state using the &lt;code&gt;each&lt;/code&gt; helper. &lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! animals/index.hbs }}
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;col-md-3&amp;quot;&amp;gt;
    &amp;lt;h2&amp;gt;Select Animals&amp;lt;/h2&amp;gt;

    {{checkbox-group
        group=animals
        selectedItems=checkboxGroup.selectedItems
        check=(action &amp;quot;check&amp;quot;)
    }}
  &amp;lt;/div&amp;gt;

  &amp;lt;div class=&amp;quot;col-md-9&amp;quot;&amp;gt;
    &amp;lt;h3&amp;gt;Selected Animals&amp;lt;/h3&amp;gt;
    &amp;lt;table class=&amp;quot;table table-bordered&amp;quot;&amp;gt;
      &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;th&amp;gt;ID&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Species&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/thead&amp;gt;

      &amp;lt;tbody&amp;gt;
        {{#each checkboxGroup.selectedItems as |animal|}}
          &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;{{animal.id}}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{animal.species}}&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;{{animal.name}}&amp;lt;/td&amp;gt;
          &amp;lt;/tr&amp;gt;
        {{/each}}
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In our controller or routable component, we inject the service and define the action for handling the checked animal. The service&amp;#39;s bag of state is then passed into the component, keeping it as pure as possible. Although you could have just injected the service into the component, doing it this way makes things more explicit and allows the component to be decoupled from the service. &lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// animals/controller.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { &lt;span class=&quot;key&quot;&gt;inject&lt;/span&gt;: { service }, Controller } = Ember;
const OPERATION_MAP = {
  &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;addObject&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;removeObject&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
};

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Controller.extend({
  &lt;span class=&quot;key&quot;&gt;checkboxGroup&lt;/span&gt;: service(),

  &lt;span class=&quot;comment&quot;&gt;// In the future, actions will be defined in the route and passed into the &lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;// routable component as `attributes`.&lt;/span&gt;
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    check(group, item, isChecked) {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; group[OPERATION_MAP[isChecked]](item);
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As mentioned, the service itself is simple. We can define more complex behavior later, but the underlying persistence for its state is just a JavaScript array.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// checkbox-group/service.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { Service } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Service.extend({
  init() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.selectedItems = [];
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Because our behavior is simple, we don&amp;#39;t need to define a sub-classed component in this example. The &lt;code&gt;check&lt;/code&gt; action is passed in from the routable component / controller, so using closure actions in the component&amp;#39;s template means that we don&amp;#39;t have to cast &lt;code&gt;sendAction&lt;/code&gt;s into the void.&lt;/p&gt;

&lt;p&gt;In our component&amp;#39;s template, we make use of small, composable helpers. These helpers are just simple JavaScript functions under the hood, and because they have return values, we can use them as Handlebars sub-expressions where we might have once defined a computed property. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;contains&lt;/code&gt; helper doesn&amp;#39;t ship with Ember, but the function itself is &lt;a href=&quot;https://github.com/poteto/component-best-practices/blob/master/app%2Fhelpers%2Fcontains.js?ts=2&quot;&gt;one line of code&lt;/a&gt;. There are a bunch of useful addons that add helpers such as these to your application â for example, &lt;a href=&quot;https://www.npmjs.com/package/ember-truth-helpers&quot;&gt;&lt;code&gt;ember-truth-helpers&lt;/code&gt;&lt;/a&gt; is an addon I find myself using in almost all my apps.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! checkbox-group/template.hbs }}
{{#each group as |item|}}
  &amp;lt;div class=&amp;quot;checkbox&amp;quot;&amp;gt;
    &amp;lt;label for={{concat &amp;quot;item-&amp;quot; item.id}}&amp;gt;
      {{one-way-input
          id=(concat &amp;quot;item-&amp;quot; item.id)
          class=&amp;quot;checkbox&amp;quot;
          type=&amp;quot;checkbox&amp;quot;
          checked=(contains selectedItems item)
          update=(action this.attrs.check selectedItems item)
      }} {{item.name}} &amp;lt;span class=&amp;quot;label label-default&amp;quot;&amp;gt;{{item.species}}&amp;lt;/span&amp;gt;
    &amp;lt;/label&amp;gt;
  &amp;lt;/div&amp;gt;
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As mentioned in my &lt;a href=&quot;https://dockyard.com/blog/2015/11/16/best-practices-functional-programming-and-the-observer-effect&quot;&gt;previous post&lt;/a&gt;, the &lt;a href=&quot;https://github.com/dockyard/ember-one-way-input&quot;&gt;&lt;code&gt;ember-one-way-input&lt;/code&gt;&lt;/a&gt; addon is an easy way to start using one-way bindings today. &lt;/p&gt;

&lt;p&gt;I hope this simple example illustrates how you can build maintainable and performant apps with some of my favorite features of Ember â helpers, closure actions, components, and one-way bindings.&lt;/p&gt;

&lt;h2&gt;A word of caution about Services&lt;/h2&gt;

&lt;p&gt;As the clichÃ© goes, &amp;quot;with great power...&amp;quot;. Because services in Ember are singletons, it becomes tempting to make multiple services and inject them everywhere. &lt;/p&gt;

&lt;p&gt;If your main reason for creating a service is to use it as a &amp;quot;global&amp;quot;, that is generally a code smell because dependencies become implicit (we learned earlier that this is a bad thing) and parts of your application become tightly coupled. Instead, expose data and actions via interfaces to keep your code decoupled and explicit. Remember the Principle of Least Power, and only use a service when strictly necessary!&lt;/p&gt;

&lt;h3&gt;So when should I use a service?&lt;/h3&gt;

&lt;p&gt;I like this &lt;a href=&quot;http://stackoverflow.com/a/142450/4259952&quot;&gt;Stack Overflow answer&lt;/a&gt; on when you should use a singleton. Essentially, you should only use one when you can only have a single instance throughout your application. For example, a shopping cart, &lt;a href=&quot;https://github.com/poteto/ember-cli-flash&quot;&gt;flash messages&lt;/a&gt; or activity feed could be great candidates for a service.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Speeding up Elixir project build times on Travis CI</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/12/02/speeding-up-elixir-project-build-times-on-travis-ci" />
    <id>https://dockyard.com/blog/2015/12/02/speeding-up-elixir-project-build-times-on-travis-ci</id>
    <category term="travis-ci" label="Travis Ci"/><category term="continuous-integration" label="Continuous Integration"/><category term="elixir" label="Elixir"/>
    <published>2015-12-02 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Elixir is fast, very fast. So fast that a good chunk of &lt;a href=&quot;https://en.wikipedia.org/wiki/Continuous_integration&quot;&gt;Continuous
Integration&lt;/a&gt; jobs on &lt;a href=&quot;http://travis-ci.org&quot;&gt;Travis CI&lt;/a&gt; for our Phoenix projects were spent in
fetching dependencies (this is very small, but still a few seconds) and
then compiling all of the dependencies.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;re willing to deal with getting a failed build once in a while
then you can significantly speed up the CI jobs by caching certain
assets. Specifically the &lt;code&gt;_build/&lt;/code&gt; and &lt;code&gt;deps/&lt;/code&gt; directories.&lt;/p&gt;

&lt;p&gt;This strategy can be used on any CI service but the example here is for
Travis CI. Simply add the following to your &lt;code&gt;.travis.yml&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;highlight yml &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;key&quot;&gt;cache&lt;/span&gt;:
  &lt;span class=&quot;key&quot;&gt;directories&lt;/span&gt;:
    - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;_build&lt;/span&gt;&lt;/span&gt;
    - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;deps&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We saw a big reduction in total Pull Request CI test run time
&lt;img src=&quot;http://i.imgur.com/jst9V2C.png&quot; alt=&quot;total-jobs&quot;&gt;&lt;/p&gt;

&lt;p&gt;Here is a comparison of the individual jobs&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/efm7IPa.png&quot; alt=&quot;before&quot;&gt;&lt;/p&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/LfXAuSk.png&quot; alt=&quot;after&quot;&gt;&lt;/p&gt;

&lt;p&gt;If you are getting a failing build when you believe you shouldn&amp;#39;t, the
issue could be the cache. You can simply &lt;a href=&quot;https://docs.travis-ci.com/user/caching/#Clearing-Caches&quot;&gt;clear the cache and start it
from scratch at any time&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Comparing dates and times in Elixir with Ecto</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/11/30/comparing-date-time-in-elixir-with-ecto" />
    <id>https://dockyard.com/blog/2015/11/30/comparing-date-time-in-elixir-with-ecto</id>
    <category term="phoenix" label="Phoenix"/><category term="ecto" label="Ecto"/><category term="elixir" label="Elixir"/>
    <published>2015-11-30 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;If you are working with &lt;code&gt;Ecto.DateTime&lt;/code&gt; in your Phoenix
application you may make a comparison of two variables at some point:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;d1 = {{2015, 11, 30}, {0, 0, 0}} |&amp;gt; Ecto.DateTime.from_erl
d2 = {{2015, 11, 29}, {0, 0, 0}} |&amp;gt; Ecto.DateTime.from_erl

assert d1 &amp;gt; d2
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above ends up passing the assertion, but only by coincidence. What
if you had a situation where you wanted to assert a comparison between
today and tomorrow, but tomorrow ends up being a different month:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;d1 = {{2015, 12, 1}, {0, 0, 0}} |&amp;gt; Ecto.DateTime.from_erl
d2 = {{2015, 11, 30}, {0, 0, 0}} |&amp;gt; Ecto.DateTime.from_erl

assert d1 &amp;gt; d2
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above assertion fails. If you think it seems odd that &lt;code&gt;December 1, 2015&lt;/code&gt;
would be less than &lt;code&gt;November 30, 2015&lt;/code&gt; you&amp;#39;d be correct. To understand
why we have to see what &lt;code&gt;Ecto.DateTime.from_erl/1&lt;/code&gt; returns:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{2015, 12, 1}, {0, 0, 0}} |&amp;gt; Ecto.DateTime.from_erl

# =&amp;gt; #Ecto.DateTime&amp;lt;2015-11-30T00:00:00Z&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is an &lt;a href=&quot;http://elixir-lang.org/getting-started/structs.html&quot;&gt;Elixir Struct&lt;/a&gt;. The properties of the struct are not
ordered, so the comparison does not actually understand the structure of
datetime and how to compare properly. In this case it appears that the
day values are being compared before the month values, resulting in a
&lt;code&gt;false&lt;/code&gt; assertion. To better understand this we need to take a look at
the Erlang documentation for Maps (which are just Structs):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maps are ordered by size, two maps with the same size are compared by
keys in ascending term order and then by values  in key order. In maps
key order integers types are considered less than floats types.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To do a proper datetime comparison between two &lt;code&gt;Ecto.DateTime&lt;/code&gt; structs we have to convert to a
tuple. We can do this by using &lt;code&gt;Ecto.DateTime.to_erl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;d1 = #Ecto.DateTime&amp;lt;2015-12-01T00:00:00Z&amp;gt;
d2 = #Ecto.DateTime&amp;lt;2015-11-30T00:00:00Z&amp;gt;

assert Ecto.DateTime.to_erl(d1) &amp;gt; Ecto.DateTime.to_erl(d2)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This can be cumbersome to write all the time. Thankfully Ecto comes with
a nice &lt;a href=&quot;http://hexdocs.pm/ecto/Ecto.DateTime.html#compare/2&quot;&gt;&lt;code&gt;Ecto.DateTime.compare/2&lt;/code&gt;&lt;/a&gt; function:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;d1 = #Ecto.DateTime&amp;lt;2015-12-01T00:00:00Z&amp;gt;
d2 = #Ecto.DateTime&amp;lt;2015-11-30T00:00:00Z&amp;gt;

assert Ecto.DateTime.compare(d1, d2) == :gt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Ecto.DateTime.compare/2&lt;/code&gt; takes two time structs and compares the first
to the second. The result will be &lt;code&gt;:eq&lt;/code&gt;, &lt;code&gt;:lt&lt;/code&gt;, or &lt;code&gt;:gt&lt;/code&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Handlebars&#39;s Overlooked {{#each}} {{else}} Conditional Block</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/11/23/ember-practices-each-else" />
    <id>https://dockyard.com/blog/2015/11/23/ember-practices-each-else</id>
    <category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/><category term="best-practices" label="Best Practices"/>
    <published>2015-11-23 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Doug Yun</name></author>
    <summary>The Handlebars {{#each}} block trick that folks always forget</summary>
    <content type="html">&lt;p&gt;In the past few months, my esteemed coworkers have written about &lt;a href=&quot;https://dockyard.com/blog/categories/best-practices&quot;&gt;various
Ember best practices&lt;/a&gt;. To follow suit, I&amp;#39;d like to
reintroduce an often forgotten Handlebars trick.&lt;/p&gt;

&lt;p&gt;How many times have you stumbled across a template that wrapped an
&lt;code&gt;{{#each}}&lt;/code&gt; block with an outer &lt;code&gt;{{#if}}&lt;/code&gt; conditional block?&lt;/p&gt;

&lt;h2&gt;The Verbose&lt;/h2&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! if-and-each-usage.hbs}}

{{#if footballTeams}}
  {{#each footballTeams as |team|}}
    Teamname: {{team.name}}
    City: {{team.city}}
    Mascot: {{team.mascot}}
  {{/each}}
{{else}}
  No teams to display!
{{/if}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Logically, this makes sense. If there aren&amp;#39;t &lt;code&gt;footballTeams&lt;/code&gt; to iterate
through, we render out a message.&lt;/p&gt;

&lt;p&gt;However, the result is an unnecessary conditional! Thankfully, the
&lt;code&gt;{{#each}}&lt;/code&gt; block helper provides us with a more terse solution.&lt;/p&gt;

&lt;h2&gt;The Succinct&lt;/h2&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! each-else-usage.hbs}}

{{#each footballTeams as |team|}}
  Teamname: {{team.name}}
  City: {{team.city}}
  Mascot: {{team.mascot}}
{{else}}
  No teams to display!
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We don&amp;#39;t need the outer &lt;code&gt;{{#if}}&lt;/code&gt; block, and we simply can add an
&lt;code&gt;{{else}}&lt;/code&gt; path within our &lt;code&gt;{{#each}}&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;Although, the change here seems quite trivial, it immediately cleans
up readibility (which is a huge win in my book).&lt;/p&gt;

&lt;h2&gt;More to Come&lt;/h2&gt;

&lt;p&gt;If you&amp;#39;ve enjoyed these &lt;a href=&quot;https://dockyard.com/blog/categories/best-practices&quot;&gt;series of best practices&lt;/a&gt;, stay tuned,
we&amp;#39;ll be writing more posts soon after the holidays! Thanks!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Phoenix is not Rails</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/11/18/phoenix-is-not-rails" />
    <id>https://dockyard.com/blog/2015/11/18/phoenix-is-not-rails</id>
    <category term="phoenix" label="Phoenix"/><category term="ruby" label="Ruby"/><category term="rails" label="Ruby on Rails"/><category term="elixir" label="Elixir"/>
    <published>2015-11-18 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Chris McCord</name></author>
    <summary>Phoenix is not Rails, but some ideas are borrowed</summary>
    <content type="html">&lt;p&gt;In his yearly recap last December, Brian went public with his &lt;a href=&quot;https://dockyard.com/blog/2014/12/28/lessons-learned-three-years-running-a-software-consultancy&quot;&gt;plans to transition the company over to Elixir and Phoenix development&lt;/a&gt;. Throughout this year, he found it was a smooth transition for the team &lt;a href=&quot;https://dockyard.com/blog/2015/10/29/how-long-it-took-our-team-to-move-from-rails-to-phoenix&quot;&gt;going from primarily Rails to Phoenix powered applications&lt;/a&gt;.
On the surface, Phoenix shares some familiar conventions with Rails that lets folks jump into new applications and contribute early to a project â on their way to greater mastery. Complete mastery will take a bit more practice than knowing a few shared conventions, but the similar-at-a-glance features has enticed Ruby teams to get involved and many are delighted to get up and running quickly. Unfortunately, it has also led to wrong assumptions about Phoenix&amp;#39;s likeness to Rails, causing some to miss the important differences around their core philosophies.&lt;/p&gt;

&lt;p&gt;It is common in the Ruby community to say that there are Rails developers and Ruby developers. We don&amp;#39;t expect this to happen with Phoenix. Although Phoenix of course introduces its own abstractions, ultimately writing a Phoenix application is writing an Elixir application. Testing Phoenix code is testing Elixir functions. This post aims to address these ideas by comparing the similarities and differences between Phoenix and Rails and why it matters.&lt;/p&gt;

&lt;h2&gt;Similarities&lt;/h2&gt;

&lt;p&gt;Most of the phoenix-core team comes from a Rails-heavy background, so it&amp;#39;s natural we borrow some of the great ideas Rails brings to the table, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both focus on productivity, from client to server side&lt;/li&gt;
&lt;li&gt;Both provide a default directory structure, although Phoenix simply relies on the structure imposed by Elixir applications&lt;/li&gt;
&lt;li&gt;Both are MVC frameworks (Phoenix does a functional twist on the architecture though) with a router sitting on top&lt;/li&gt;
&lt;li&gt;Both provide a default stack with relational databases (sqlite3 for Rails, PostgreSQL for Phoenix)&lt;/li&gt;
&lt;li&gt;Both promote security best practices in their default stack&lt;/li&gt;
&lt;li&gt;Both ship with a default toolkit for writing and running tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Differences&lt;/h2&gt;

&lt;p&gt;With a few similarities, comes major differences. From how you structure your applications, recover from failure, debug your systems, or talk to a remote client, Phoenix takes an approach that few run-times can offer. We embrace Elixir and OTP conventions in Phoenix so that your Phoenix application is only a component of your greater application infrastructure. This deviation from Rails has effects throughout the stack.&lt;/p&gt;

&lt;h3&gt;Applications&lt;/h3&gt;

&lt;p&gt;There is no such thing as a &amp;quot;Phoenix application&amp;quot;. Your Phoenix projects are first and foremost Elixir applications, which relies on Phoenix to provide part of its functionality. This means there is one way to build, run, and deploy your applications â the Elixir way.&lt;/p&gt;

&lt;h4&gt;Why it matters: no singletons&lt;/h4&gt;

&lt;p&gt;In Rails there is a single application that&amp;#39;s accessible via &lt;code&gt;Rails.application&lt;/code&gt;. Rails runs the show, from starting the application, configuration, and even running command line tasks. As an inherent limitation of this approach, you cannot run two Rails applications side by side. If you need sharing, you need to carefully break it apart into engines and learn a new set of rules.&lt;/p&gt;

&lt;p&gt;With Phoenix, nothing is global. There is no monolith. A new Phoenix application will include one Endpoint, one Router, and one PubSub Server, but you are free to add more. With no global state or global servers, you can break your application into pieces as your infrastructure grows.&lt;/p&gt;

&lt;h4&gt;Why it matters: startup and shutdown&lt;/h4&gt;

&lt;p&gt;Elixir conventions structure your projects as small composable &amp;quot;applications&amp;quot; that can be started and stopped as a unit. The trail usually goes like this (using Phoenix itself as an example):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Every application has a specification, that may specify which module to invoke when the application will be initialized:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def application do
[mod: {Phoenix, []},
 applications: [:plug, :poison, :logger, :eex],
...]
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/phoenixframework/phoenix/blob/9f9c4663b304a3ff885cc8356cad278e100eb499/mix.exs#L28-L38&quot;&gt;source&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If a module is specified, the &lt;code&gt;start/2&lt;/code&gt; function of this module is invoked:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule Phoenix do
def start(_type, _args) do
  ...
  Phoenix.Supervisor.start_link
end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/phoenixframework/phoenix/blob/7692aef141f6eab5ad9a0e88875f42c8b02b117d/lib/phoenix.ex#L3%20%200&quot;&gt;source&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;start/2&lt;/code&gt; function must return the identifier of a supervised process, such as &lt;code&gt;Phoenix.Supervisor.start_link&lt;/code&gt; above&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/phoenixframework/phoenix/blob/7692aef141f6eab5ad9a0e88875f42c8b02b117d/lib/phoenix.ex#L41&quot;&gt;source&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A similar flow happens when stopping your application. The consequence is that it doesn&amp;#39;t matter if you are using Phoenix or not, every application has its own and contained start/stop mechanism.&lt;/p&gt;

&lt;p&gt;This is a stark contrast to Rails initialization which is extremely complex and requires extensions to hijack a single, sequential initialization flow. For a Rails 4.2.2 app:&lt;/p&gt;
&lt;div class=&quot;highlight irb &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;error&quot;&gt;$&lt;/span&gt; rails c
&lt;span class=&quot;constant&quot;&gt;Loading&lt;/span&gt; development environment (&lt;span class=&quot;constant&quot;&gt;Rails&lt;/span&gt; &lt;span class=&quot;float&quot;&gt;4.2&lt;/span&gt;.&lt;span class=&quot;error&quot;&gt;2&lt;/span&gt;)
irb(main):&lt;span class=&quot;integer&quot;&gt;001&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;&amp;gt; &lt;span class=&quot;constant&quot;&gt;Rails&lt;/span&gt;.application.initializers.length
=&amp;gt; &lt;span class=&quot;integer&quot;&gt;74&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Those are 74 snippets of code (Ruby blocks) spread around multiple files in a non-specified order! Having control of the initialization logic is extremely important to know exactly what your app is running and to keep boot times fast.&lt;/p&gt;

&lt;h4&gt;Why it matters: monitoring and introspection&lt;/h4&gt;

&lt;p&gt;By relying on applications, you gain supervision, fault tolerance, and introspection into your running system. We can easily view our applications running as a unit, or as a whole with tools like observer:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/SehijaI.png&quot; alt=&quot;Imgur&quot;&gt;&lt;/p&gt;

&lt;p&gt;The beauty is, your project will start as a single application and it may (or may not) be broken into multiple applications naturally, be they all running in a single node or in a service oriented architecture. We pay no upfront cost because the runtime is built on tried and true patterns. In fact, we will cover such an example in an upcoming chapter of the &lt;a href=&quot;https://pragprog.com/book/phoenix/programming-phoenix&quot;&gt;Programming Phoenix book&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Request life-cycle&lt;/h3&gt;

&lt;p&gt;Phoenix provides fantastic performance out of the box, &lt;a href=&quot;https://gist.github.com/omnibs/e5e72b31e6bd25caf39a&quot;&gt;with benchmarks&lt;/a&gt; to prove it. The request/response life-cycle in Phoenix differs greatly from the approach Rails takes with Rack.&lt;/p&gt;

&lt;h4&gt;Why it matters: easy to understand&lt;/h4&gt;

&lt;p&gt;Explicit &amp;gt; Implicit. Almost Always. Phoenix favors explicitness in most of its stack. For example, when generating your Phoenix application, you can see all the &amp;quot;plugs&amp;quot; your request goes through in &lt;code&gt;lib/my_app/endpoint.ex&lt;/code&gt;. Where Rails segregates Rack middleware to a side-loaded part of the application, Phoenix makes all plugs explicit. You have an instant, at-a-glance look into your request life-cycle by viewing the plugs in your endpoint and router.&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule MyApp.Endpoint do
  use Phoenix.Endpoint, otp_app: :my_app

  socket &amp;quot;/socket&amp;quot;, MyApp.UserSocket
  plug Plug.Static, at: &amp;quot;/&amp;quot;, from: :my_app, gzip: false, only: ~w(css images js)
  plug Plug.RequestId
  plug Plug.Logger
  plug Plug.Parsers, parsers: [:urlencoded, :multipart, :json], pass: [&amp;quot;*/*&amp;quot;]
  plug Plug.MethodOverride
  plug Plug.Head
  plug Plug.Session, store: :cookie
  plug MyApp.Router
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A request starts in your Endpoint, flows through the explicit plug &amp;quot;base middleware&amp;quot;, and is handed off to your Router, which itself as just a plug. Then the router applies its own plugs before handing off to a controller, which is (you guessed it!), a Plug. A single level of abstraction throughout the entire stack makes reasoning about your request life-cycle as clear as possible. It also allows easy third-party package integration because of the simplicity of the Plug contract.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s compare two very similar looking controllers to see how Phoenix&amp;#39;s functional approach with Plug makes the code easier to understand:&lt;/p&gt;

&lt;p&gt;controller.rb:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;before_action &lt;span class=&quot;symbol&quot;&gt;:find_user&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;instance-variable&quot;&gt;@post&lt;/span&gt; = &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.posts.find(params[&lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;])
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;find_user&lt;/span&gt;
  &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.find(params[&lt;span class=&quot;symbol&quot;&gt;:user_id&lt;/span&gt;])
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;controller.ex:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;plug :find_user

def show(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id}) do
  post = conn.assigns.user |&amp;gt; assoc(:posts) |&amp;gt; Repo.get(id)
  render conn, &amp;quot;show.html&amp;quot;, post: post
end

defp find_user(conn, _) do
  assign(conn, :user, Repo.get(User, conn.params[&amp;quot;user_id&amp;quot;]))
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Unless you&amp;#39;re a seasoned Rails developer, you wouldn&amp;#39;t know that &lt;code&gt;show&lt;/code&gt; calls &lt;code&gt;render &amp;quot;show.html&amp;quot;&lt;/code&gt; implicitly. Even if it was called explicitly, you would have to know that all instance variables are copied from the controller instance to the view instance, which is a layer of complexity that few realize when first getting into Rails development. Convention over configuration is a Good Thing, but there&amp;#39;s a threshold where implicit behavior sacrifices clarity. Phoenix optimizes for clarity, in a way that we think strikes a perfect balance with easy to use APIs. Beyond that, as an Object Oriented programmer you must be aware of all the implicit state of the instance, such as the &lt;code&gt;params&lt;/code&gt; hash, the &lt;code&gt;request&lt;/code&gt; object, and any instance variables set in &lt;code&gt;before_action&lt;/code&gt; filters. In Phoenix, everything is explicit. The &lt;code&gt;conn&lt;/code&gt; is our bag of data and line of communication with the webserver. We pass it along through a pipeline of functions called plugs, transforming the connection, and sending response(s) as needed.&lt;/p&gt;

&lt;h4&gt;Why it matters: easy to test&lt;/h4&gt;

&lt;p&gt;Functional programming and the Plug contract make testing your controllers in isolation, or integration testing your entire endpoint, only a matter of passing a &lt;code&gt;conn&lt;/code&gt; through the plug pipeline and asserting against the result. Additionally, controller actions in Phoenix are just functions, without implicit state. If we need to test the controller in isolation, we call the function!&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;test &amp;quot;sends 404 when user is not found&amp;quot; do
  conn = MyController.show(conn(), %{&amp;quot;id&amp;quot; =&amp;gt; &amp;quot;not-found&amp;quot;})
  assert conn.status == 404
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There&amp;#39;s no stumbling with setting up controller instances thanks to functional programming. And when we need to fully integration test through the endpoint, Phoenix just calls the pipeline of functions:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;test &amp;quot;shows users&amp;quot; do
  conn = get conn(), &amp;quot;/users/123&amp;quot;
  assert %{id: &amp;quot;123&amp;quot;} = json_response(conn, :ok)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Phoenix views follow the same principle as controllers: they are all just functions, there is no implicit data sneaking in!&lt;/p&gt;

&lt;h4&gt;Why it matters: easy to share code&lt;/h4&gt;

&lt;p&gt;Once you end-up relying on controller instance variables and methods, a method that you wrote to run in a Rails controller cannot be easily moved to a Rack middleware because it relies on many controller internals.&lt;/p&gt;

&lt;p&gt;Since plugs are just functions, you know what is coming in and you know what is going out. There is one abstraction for the entire HTTP stack: whether in the endpoint, router or controller. For example, let&amp;#39;s say you want to apply an &lt;code&gt;AdminAuthentication&lt;/code&gt; plug to all &lt;code&gt;&amp;quot;/admin&amp;quot;&lt;/code&gt; requests, as well as a special &lt;code&gt;DashboardController&lt;/code&gt;. We use the same plug at both the Router and Controller levels of abstraction:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule MyApp.Router do
  pipeline :browser do
    plug :fetch_session
    ...
    plug :protect_from_forgery
  end

  pipeline :admin do
    plug AdminAuthentication
  end

  scope &amp;quot;/&amp;quot; do
    get &amp;quot;/dashboard&amp;quot;, DashboardController
  end

  scope &amp;quot;/admin&amp;quot; do
    pipe_through [:browser, :admin] # plugged for all routes in this scope

    resources &amp;quot;/orders&amp;quot;, OrderController
  end
end

defmodule MyApp.DashboardController do
  plug AdminAuthentication # plugged only on this controller

  def show(conn, _params) do
    render conn, &amp;quot;show.html&amp;quot;
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Since we use &lt;code&gt;plug&lt;/code&gt; at all levels of the stack, we can plug in the &lt;code&gt;AdminAuthentication&lt;/code&gt; plug in the Router and controller for fine-grained request rules. In Rails, you would inherit from an &lt;code&gt;AdminController&lt;/code&gt;, but the clarity of what transformations apply to your request is lost. You have to track down the inheritance tree to find out which rules are applied and where. In Phoenix, router pipelines make the concerns of your request explicit.&lt;/p&gt;

&lt;h3&gt;Channels&lt;/h3&gt;

&lt;p&gt;Phoenix from day one was built to take on the challenges of the modern, highly connected, real-time web. Channels bring transport agnostic real-time connections to your application, which can scale to &lt;a href=&quot;http://www.phoenixframework.org/blog/the-road-to-2-million-websocket-connections&quot;&gt;millions of clients on a single server&lt;/a&gt;. This deviates from Rails where historically real-time features have been second-class.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/7CHc1Lh.png&quot; alt=&quot;Imgur&quot;&gt;&lt;/p&gt;

&lt;h4&gt;Why it matters: the web is evolving&lt;/h4&gt;

&lt;p&gt;Phoenix Channels target the Web beyond the browser. The web is evolving to include &lt;em&gt;connected devices&lt;/em&gt; (phones, watches, smart toasters) â one of which is a browser. We need a framework that can evolve with changing and new protocols alike. That&amp;#39;s why Channels are transport agnostic, with native channel clients available on iOS, Android, and Windows platforms. You can see this in action with a &lt;a href=&quot;https://vimeo.com/136679715&quot;&gt;Phoenix chat app running natively on a browser, iPhone, and Apple Watch&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Why it matters: fast performance, with less dependencies&lt;/h4&gt;

&lt;p&gt;Rails&amp;#39; recent entry into real-time features with &lt;a href=&quot;https://github.com/rails/actioncable/blob/master/actioncable.gemspec#L17-L25&quot;&gt;Action Cable bring a heavy list of dependencies: Faye, Celluloid, EventMachine, Redis, to name a few&lt;/a&gt;. Because Phoenix runs on the Erlang Virtual Machine, Phoenix gets real-time features out of the box from the run-time. The run-time is distributed, allowing Phoenix to skip any operational dependency like Redis to orchestrate PubSub messages across servers.&lt;/p&gt;

&lt;h3&gt;Naming&lt;/h3&gt;

&lt;p&gt;Phoenix does not impose strict naming conventions, like we see in Rails.&lt;/p&gt;

&lt;h4&gt;Why it matters: easy to learn&lt;/h4&gt;

&lt;p&gt;Phoenix does not tie module names to the filename. Rails requires a &lt;code&gt;UsersController&lt;/code&gt; to be located in a file named &lt;code&gt;users_controller.rb&lt;/code&gt;. We agree conventions like these are good, but Phoenix does not care about such tight restrictions. Instead we promote sane defaults, but are flexible to individual requirements. Naming also creates a lot of confusion for people who learn Rails first then try to write Ruby applications. Because Rails depends on &lt;code&gt;const_missing&lt;/code&gt; to require files based upon the class name convention of file path, knowing how to require files in a regular Ruby application is a bit of a mystery for programmers looking to move their knowledge outside of Rails.&lt;/p&gt;

&lt;p&gt;Phoenix includes a &amp;quot;web&amp;quot; directory where you put controllers, views, etc, but it only exists for code reloading purposes which gives you refresh-driven-development.&lt;/p&gt;

&lt;p&gt;Phoenix also does not impose singular and plural naming rules. Rails naming rules can confuse beginners and advanced developers alike: models use singular names, controllers use plural ones, URL helpers mix both, and so on. Phoenix consistently uses singular rules, as any other Elixir code. You may use plural names for your tables and router paths, but those are explicitly written at your system boundaries.&lt;/p&gt;

&lt;h3&gt;Assets&lt;/h3&gt;

&lt;p&gt;Phoenix uses a tool named &lt;a href=&quot;http://brunch.io&quot;&gt;brunch&lt;/a&gt; by default for handling static assets, but it allows you to bring your own JavaScript build tool, instead of building one specific to the framework, like Rails does with the asset pipeline. Phoenix also leverages its channel layer to provide live-reload of changes out of the box.&lt;/p&gt;

&lt;h4&gt;Why it matters: ES6/ES2015 is the future&lt;/h4&gt;

&lt;p&gt;Phoenix promotes ES6/ES2015 instead of CoffeeScript, by supporting ES2015 out of the box for new projects. CoffeeScript served its noble purpose to push the industry forward. ES2015 and its &lt;a href=&quot;https://babeljs.io&quot;&gt;first-class transpilers&lt;/a&gt; are the clear way forward.&lt;/p&gt;

&lt;h4&gt;Why it matters: live-reload is an essential feature&lt;/h4&gt;

&lt;p&gt;Phoenix ships with live reload out of the box. As soon as you change a .js or .css file, it is automatically reloaded in your browser. Once you add this feature to your development work-flow, it&amp;#39;s one you can&amp;#39;t live without.&lt;/p&gt;

&lt;h2&gt;Wrap-up&lt;/h2&gt;

&lt;p&gt;Regardless of your background, you&amp;#39;ll find Phoenix borrows from great ideas that came before it, while using Elixir to carve its own path to take on the modern web.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Functional Programming and the Observer Effect</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/11/16/best-practices-functional-programming-and-the-observer-effect" />
    <id>https://dockyard.com/blog/2015/11/16/best-practices-functional-programming-and-the-observer-effect</id>
    <category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/><category term="best-practices" label="Best Practices"/>
    <published>2015-11-16 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Don&#39;t use observers.</summary>
    <content type="html">&lt;p&gt;My awesome colleagues have written about patterns and &lt;a href=&quot;https://dockyard.com/blog/categories/best-practices&quot;&gt;best practices&lt;/a&gt; we use at DockYard, covering everything from the &lt;a href=&quot;https://dockyard.com/blog/2015/10/19/2015-dont-dont-override-init&quot;&gt;Ember&lt;/a&gt; &lt;a href=&quot;https://dockyard.com/blog/2015/09/18/ember-best-practices-avoid-leaking-state-into-factories&quot;&gt;Object&lt;/a&gt; &lt;a href=&quot;https://dockyard.com/blog/2015/11/09/best-practices-extend-or-mixin&quot;&gt;model&lt;/a&gt; and &lt;a href=&quot;https://dockyard.com/blog/2015/09/25/ember-best-practices-acceptance-tests&quot;&gt;better acceptance tests&lt;/a&gt;, to &lt;a href=&quot;https://dockyard.com/blog/2015/10/05/ember-best-practices-using-native-input-elements&quot;&gt;native inputs&lt;/a&gt; and &lt;a href=&quot;https://dockyard.com/blog/2015/10/29/ember-best-practice-stop-bubbling-and-use-closure-actions&quot;&gt;closure actions&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Today, I&amp;#39;d like to write about something that is close to all our hearts â &lt;span title=&quot;Every time you use an observer, Stefan Penner dies a little inside.&quot;&gt;observers&lt;/span&gt;; and a topic I think about a lot â functional programming (FP). I&amp;#39;d like to take you through a tour of refactoring away from observers in your application and freeing yourself from the shackles of the &amp;quot;observer effect&amp;quot;. Let&amp;#39;s get started!&lt;/p&gt;

&lt;h2&gt;Side effects wreck projects&lt;/h2&gt;

&lt;p&gt;In science, the term &lt;a href=&quot;https://en.wikipedia.org/wiki/Observer_effect_(physics)&quot;&gt;&amp;quot;observer effect&amp;quot;&lt;/a&gt; refers to the changes that are effected on some phenomenon simply by observing it. This is often because of instruments that alter the state of what they observe in some manner.&lt;/p&gt;

&lt;p&gt;Sound familiar? Funnily enough, the same effect can probably be found in your Ember application if you use observers. For reasons we&amp;#39;ll cover in this post, &lt;a href=&quot;https://www.youtube.com/watch?v=7PUX27RKCq0&quot;&gt;observers are an anti-pattern&lt;/a&gt; and should be avoided, as it makes it difficult to reason about and to debug your application.&lt;/p&gt;

&lt;h2&gt;Difficult to reason about? Â¯\_(ã)_/Â¯&lt;/h2&gt;

&lt;p&gt;&amp;quot;Difficult to reason about&amp;quot; is a term that is commonly thrown around â but what exactly does it mean? Informally, it means being able to tell what a program will do just by looking at its code. That is, running the program &lt;em&gt;should not&lt;/em&gt; lead to unexpected surprises. We strive to make our applications easy to reason about because it leads to more maintainable code that is easier to debug and test.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;That is, running the program should not lead to unexpected surprises.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since JavaScript isn&amp;#39;t a purely functional language, it does not enforce immutability by default. Its mutable data structures can sometimes lead to surprising and unintuitive results (making some JavaScript applications difficult to reason about), so various attempts have been made to introduce immutability to the language. &lt;/p&gt;

&lt;p&gt;For example, &lt;a href=&quot;https://github.com/clojure/clojurescript&quot;&gt;ClojureScript&lt;/a&gt; and &lt;a href=&quot;http://elm-lang.org/&quot;&gt;Elm&lt;/a&gt; are functional languages that compile down to JavaScript. &lt;a href=&quot;https://swannodette.github.io/mori/&quot;&gt;Mori&lt;/a&gt; and &lt;a href=&quot;https://facebook.github.io/immutable-js/&quot;&gt;immutable.js&lt;/a&gt; are also excellent libraries that provide immutable data structures you can use in vanilla JavaScript. These tools bring in bits of FP philosophy into JavaScript applications, and have become increasingly popular in front-end development thanks to the introduction of &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt; and the &lt;a href=&quot;https://facebook.github.io/flux/docs/overview.html#content&quot;&gt;Flux pattern&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;The &amp;quot;rise&amp;quot; of FP in front end development&lt;/h2&gt;

&lt;p&gt;FP is not a new programming paradigm â it&amp;#39;s been around for a while since the introduction of LISP in the late 50s. However, it&amp;#39;s only in recent times that we&amp;#39;ve seen FP languages become more mainstream, most notably with &lt;a href=&quot;http://elixir-lang.org/&quot;&gt;Elixir&lt;/a&gt;, which combines the elegance and productivity of Ruby with the performance of the Erlang VM.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The combination of Ember&amp;#39;s conventions (over configuration), Glimmer, and DDAU means that just like Elixir, Ember developers too can find the sweet spot of having both productivity and performance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why is &lt;a href=&quot;https://www.youtube.com/watch?v=aeh5Fmh_tmw&quot;&gt;FP useful&lt;/a&gt; for building front end applications? React taught us that it is surprisingly cheap to diff the changes on the DOM, and to perform a series of updates to sync the DOM with its virtual representation. In other words, React made its &lt;code&gt;render&lt;/code&gt; function a pure one (one of the core principles of FP) â you always get the same output (HTML) for a given input (state). &lt;/p&gt;

&lt;p&gt;With the Flux pattern, that is taken a step further and the entire application is treated as a pure function â for a given serialized state, we can predictably render the same output each time. This has allowed Flux implementations like &lt;a href=&quot;http://redux.js.org/&quot;&gt;Redux&lt;/a&gt; the ability to have a &lt;a href=&quot;https://www.youtube.com/watch?v=xsSnOQynTHs&quot;&gt;&amp;quot;time traveling debugger&amp;quot;&lt;/a&gt;, which is only possible when you model your architecture with a FP paradigm.&lt;/p&gt;

&lt;h3&gt;Object.observe is not the answer&lt;/h3&gt;

&lt;p&gt;These philosophies have had resounding success, so much so that &lt;code&gt;Object.observe&lt;/code&gt; was &lt;a href=&quot;https://mail.mozilla.org/pipermail/es-discuss/2015-November/044684.html&quot;&gt;withdrawn&lt;/a&gt; from TC39. All this means is that &lt;em&gt;observing property changes&lt;/em&gt; are no longer the best way of building web applications, and Ember in general is moving in that direction with its &amp;quot;Data Down, Actions Up&amp;quot; (DDAU) philosophy. &lt;/p&gt;

&lt;p&gt;In 1.13.x, &lt;a href=&quot;https://www.youtube.com/watch?v=o12-90Dm-Qs&quot;&gt;Glimmer&lt;/a&gt; landed â it is Ember&amp;#39;s new rendering engine based on the same pure render semantics, and gives us fast, idempotent re-renders. The combination of Ember&amp;#39;s conventions (over configuration), Glimmer, and DDAU means that just like Elixir, Ember developers too can find the sweet spot of having both productivity and performance.&lt;/p&gt;

&lt;h2&gt;Data Down, Actions Up&lt;/h2&gt;

&lt;p&gt;Although you could bring in immutable data structures into your application (a topic for a future post!), that alone wouldn&amp;#39;t be enough. We should also strive to make our business logic as pure (free of side effects) as possible. Of course, it wouldn&amp;#39;t be possible to make &lt;em&gt;everything&lt;/em&gt; pure, as web applications inherently involve mutation (i.e. updating a user record), but it is beneficial to explicitly know and isolate the functions in your app that do have side effects.&lt;/p&gt;

&lt;p&gt;In Ember 2.x, the best way forward is &amp;quot;Data Down, Actions Up&amp;quot;. This means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One way bindings by default&lt;/li&gt;
&lt;li&gt;Explicit closure actions over side effects&lt;/li&gt;
&lt;li&gt;Components should not mutate data directly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My colleagues have already written about &lt;a href=&quot;https://dockyard.com/blog/2015/10/05/ember-best-practices-using-native-input-elements&quot;&gt;one way bindings&lt;/a&gt;, &lt;a href=&quot;https://dockyard.com/blog/2015/10/29/ember-best-practice-stop-bubbling-and-use-closure-actions&quot;&gt;closure actions&lt;/a&gt; and &lt;a href=&quot;https://dockyard.com/blog/2015/10/14/best-practices-data-down-actions-up&quot;&gt;not mutating data in Components&lt;/a&gt;, so I will leave you to do further reading in your own time.&lt;/p&gt;

&lt;p&gt;Instead, let&amp;#39;s continue the discussion above on how best to refactor away observers in your application, so that we can eliminate or reduce side effects.&lt;/p&gt;

&lt;h2&gt;Refactoring away observers&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s say we have an observer in our application that needs to check a user&amp;#39;s birthday &lt;a href=&quot;http://emberjs.jsbin.com/citiwi/edit?js,output&quot;&gt;(demo)&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// birth-day/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; moment from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;moment&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { 
  Component, 
  computed,
  get, 
  set
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;key&quot;&gt;isBirthday&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;birthDate&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,

  &lt;span class=&quot;key&quot;&gt;age&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; moment().diff(moment(get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;years&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    }
  }),

  checkBirthday() {
    let today = moment();
    let birthDate = moment(get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;));
    let isBirthday = (today.month() === birthDate.month()) &amp;amp;&amp;amp; 
      (today.day() === birthDate.day());

    set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isBirthday&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, isBirthday);
  },

  init() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.addObserver(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.checkBirthday);
  },

  willDestroy() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.removeObserver(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.checkBirthday);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the above example, we&amp;#39;re using an observer to set the &lt;code&gt;isBirthday&lt;/code&gt; flag if it is the user&amp;#39;s birthday.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{!birth-day/template.hbs}} 
{{input value=birthDate placeholder=&amp;quot;Your birthday&amp;quot;}}

&amp;lt;p&amp;gt;
  You are currently {{age}} years old.
  {{#if isBirthday}}
    Happy birthday!
  {{/if}}
&amp;lt;/p&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you find yourself setting some value (be in on the component, record or somewhere else), you can easily refactor away the observer.&lt;/p&gt;

&lt;h3&gt;Removing an observer that sets a value on the component&lt;/h3&gt;

&lt;p&gt;In this scenario, you can simply replace the observer with a CP. &lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// birth-day/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; moment from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;moment&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { 
  Component, 
  computed,
  get
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;key&quot;&gt;isBirthday&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      let today = moment();
      let birthDate = moment(get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;));

      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; (today.month() === birthDate.month()) &amp;amp;&amp;amp; 
        (today.day() === birthDate.day());
    }
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Using component lifecycle hooks&lt;/h3&gt;

&lt;p&gt;We could also move the &lt;code&gt;input&lt;/code&gt; logic out of this component, and use the &lt;a href=&quot;https://github.com/emberjs/ember.js/pull/11127&quot;&gt;new component lifecycle hooks&lt;/a&gt; to set the &lt;code&gt;isBirthday&lt;/code&gt; flag on the component.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// birth-day/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; moment from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;moment&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { 
  Component, 
  computed,
  get
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;key&quot;&gt;birthDate&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;today&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;isBirthday&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;,

  didReceiveAttrs() {
    let isBirthday = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.checkBirthday(
      moment(get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;today&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)), 
      moment(get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;))
    );

    set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isBirthday&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, isBirthday);
  },

  checkBirthday(today, birthDate)
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; (today.month() === birthDate.month()) &amp;amp;&amp;amp; 
      (today.day() === birthDate.day());
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{!index/template.hbs}} 
{{one-way-input 
    value=user.birthDate 
    update=(action (mut user.birthDate)) 
    placeholder=&amp;quot;Your birthday&amp;quot;
}}
{{happy-birthday today=today birthDate=user.birthDate}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{!birth-day/template.hbs}} 
&amp;lt;p&amp;gt;
  You are currently {{age}} years old.
  {{#if isBirthday}}
    Happy birthday!
  {{/if}}
&amp;lt;/p&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Both approaches let you remove the observer, but the &lt;code&gt;didReceiveAttrs&lt;/code&gt; example is slightly more explicit, and transforms the component into a pure one. By limiting the scope of the component, we can easily isolate the origins of data mutations. &lt;/p&gt;

&lt;h3&gt;Removing an observer that sets a value outside the component&lt;/h3&gt;

&lt;p&gt;In this situation, let&amp;#39;s say we want to update the user record&amp;#39;s &lt;code&gt;isBirthday&lt;/code&gt; flag instead. We can remove the observer by using one way input actions:&lt;/p&gt;

&lt;p&gt;By bringing in the &lt;a href=&quot;https://github.com/dockyard/ember-one-way-input&quot;&gt;&lt;code&gt;ember-one-way-input&lt;/code&gt;&lt;/a&gt; addon, we can eliminate the coupling of the component to the user record:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// birth-day/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; moment from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;moment&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { 
  Component, 
  computed,
  get
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  &lt;span class=&quot;comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    checkBirthday(birthDate) {
      birthDate = moment(birthDate);
      let today = moment();
      let isBirthday = (today.month() === birthDate.month()) &amp;amp;&amp;amp; 
        (today.day() === birthDate.day());

      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.attrs.setIsBirthday(isBirthday);
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.attrs.setBirthDate(birthDate.toDate());
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{!birth-day/template.hbs}} 
{{one-way-input 
    value=user.birthDate 
    update=(action &amp;quot;checkBirthday&amp;quot;) 
    placeholder=&amp;quot;Your birthday&amp;quot;
}}

&amp;lt;p&amp;gt;
  You are currently {{age}} years old.
  {{#if isBirthday}}
    Happy birthday!
  {{/if}}
&amp;lt;/p&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And then in the Controller:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// index/controller.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { Controller, set } = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Controller.extend({
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    setIsBirthday(isBirthday) {
      set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;user.isBirthday&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, isBirthday);
      user.save();
    },

    setBirthDate(birthDate) {
      set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;user.birthDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, birthDate);
      user.save();
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{!index/template.hbs}} 
{{happy-birthday 
    setIsBirthday=(action &amp;quot;setIsBirthday&amp;quot;) 
    setBirthdate=(action &amp;quot;setBirthdate&amp;quot;)
    isBirthday=user.isBirthday
}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the above example, we moved the logic for setting the &lt;code&gt;isBirthday&lt;/code&gt; flag out of the &lt;code&gt;happy-birthday&lt;/code&gt; component into its Controller. The component no longer needs to directly mutate state (an anti-pattern would be to set &lt;code&gt;user.isBirthday&lt;/code&gt; directly in the component), and can instead send a closure action up, leaving the Controller to decide how to handle the actions. Data now flows down to the Component, and any changes to the &lt;code&gt;input&lt;/code&gt; sends actions back up.&lt;/p&gt;

&lt;h2&gt;Who should use observers?&lt;/h2&gt;

&lt;p&gt;No one.&lt;/p&gt;

&lt;p&gt;If observers are so terrible, why are they in Ember? According to &lt;a href=&quot;https://twitter.com/stefanpenner/status/576511209278582784&quot;&gt;Stefan Penner&lt;/a&gt;, observers are used by the framework itself as a low level primitive, so that &lt;em&gt;you don&amp;#39;t need to use them yourself&lt;/em&gt;. So unless you&amp;#39;re working on a PR for Ember.js, stay away from observers. &lt;/p&gt;

&lt;p&gt;I hope you&amp;#39;ve enjoyed this post â next week, stay tuned for &lt;a href=&quot;https://twitter.com/dougyun&quot;&gt;Doug&lt;/a&gt;&amp;#39;s post on more Ember 2.x best practices!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Extend vs Mixin</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/11/09/best-practices-extend-or-mixin" />
    <id>https://dockyard.com/blog/2015/11/09/best-practices-extend-or-mixin</id>
    <category term="best-practices" label="Best Practices"/><category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/>
    <published>2015-11-09 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Romina Vargas</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Code duplication: canât live with it, &lt;em&gt;can&lt;/em&gt; live without it. As
developers, weâre always trying to find ways to DRY up our code. No
matter how big or how small an application, code duplication manages to
sneak its way into your files. So far in this Ember best practices series, weâve
learned how to write &lt;a href=&quot;https://dockyard.com/blog/2015/10/23/ember-best-practices-dynamic-dependent-keys-for-computed-properties&quot;&gt;DRYer computed properties&lt;/a&gt; and &lt;a href=&quot;https://dockyard.com/blog/2015/09/25/ember-best-practices-acceptance-tests&quot;&gt;DRYer tests&lt;/a&gt;. What
about more general application code?&lt;/p&gt;

&lt;p&gt;In Ember, there are two main concepts that we can adapt in order to
share code between different parts of our application: &lt;code&gt;Ember.Mixin&lt;/code&gt; and
&lt;code&gt;Ember.Object.extend()&lt;/code&gt;. Both of these essentially achieve the same end
result, but depending on the scenario, one may be a better bet. Let&amp;#39;s look at a
brief overview of each one.&lt;/p&gt;

&lt;h2&gt;Ember.Object.extend()&lt;/h2&gt;

&lt;p&gt;Deep down, all Ember objects that we create and interact with are an extension of the
&lt;code&gt;Ember.Object&lt;/code&gt;. &lt;code&gt;Ember.Object&lt;/code&gt; itself extends &lt;a href=&quot;http://emberjs.com/api/classes/Ember.CoreObject.html&quot;&gt;Ember.CoreObject&lt;/a&gt;, which
includes the &lt;a href=&quot;http://emberjs.com/api/classes/Ember.Observable.html&quot;&gt;Ember.Observable&lt;/a&gt; mixin, and it&amp;#39;s what gives Ember its &amp;quot;properties and
property observing functionality.&amp;quot; Without these base objects, there would be no Ember.&lt;/p&gt;

&lt;p&gt;We can create a new &lt;em&gt;subclass&lt;/em&gt; by calling the &lt;code&gt;extend()&lt;/code&gt; method on any Ember
object. This will give the new subclass all of the properties of the parent class,
as well as any properties defined in the new one. You&amp;#39;re also allowed to
overwrite any properties found in the parent by defining them in the new class.
If you&amp;#39;ve written an Ember App, you will be familiar with the following:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// routes/index.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  &lt;span class=&quot;comment&quot;&gt;// properties and methods&lt;/span&gt;
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this case, &lt;code&gt;IndexRoute&lt;/code&gt; will inherit properties, methods, and
anything else defined in the &lt;code&gt;Ember.Route&lt;/code&gt; object, as well as everything down
its prototype chain:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;IndexRoute&lt;/code&gt; &lt;strong&gt;-&gt;&lt;/strong&gt; &lt;code&gt;Ember.Route&lt;/code&gt; &lt;strong&gt;-&gt;&lt;/strong&gt; &lt;code&gt;Ember.Object&lt;/code&gt; &lt;strong&gt;-&gt;&lt;/strong&gt; &lt;code&gt;Ember.CoreObject&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Keep in mind that any properties defined in the parent object will be shared
among any child object. For this reason, you may want to
initialize certain properties inside the &lt;code&gt;init&lt;/code&gt; constructor, which gets called
whenever an instance of an object gets created. This way, each object instance
gets its own unique set of properties.&lt;/p&gt;

&lt;h2&gt;Ember.Mixin&lt;/h2&gt;

&lt;p&gt;Unlike the &lt;code&gt;Ember.Object&lt;/code&gt;, mixins donât get extended. Instead, they get
created via &lt;code&gt;Ember.Mixin.create()&lt;/code&gt;. When we include the mixin inside an
Ember object, weâre extending the constructorâs prototype. What this
means is that like using &lt;code&gt;extend()&lt;/code&gt;, any properties or functionality that is
defined inside the mixin will be shared among all classes containing this mixin.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// mixins/foo.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Mixin.create({
  &lt;span class=&quot;key&quot;&gt;bars&lt;/span&gt;: []
)};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// components/A.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; FooMixin from &lt;span class=&quot;error&quot;&gt;â&lt;/span&gt;..&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;mixins&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;foo&lt;span class=&quot;error&quot;&gt;â&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend(FooMixin);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// components/B.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; FooMixin from &lt;span class=&quot;error&quot;&gt;â&lt;/span&gt;..&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;mixins&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;foo&lt;span class=&quot;error&quot;&gt;â&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend(FooMixin);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above will result in both component A and component B sharing the same
&lt;code&gt;bars&lt;/code&gt; array. Any changes made to the array will be reflected in both
components. If you want to play around with this sharing business,
you can go &lt;a href=&quot;http://emberjs.jsbin.com/nakube/2/edit?html,js,output&quot;&gt;here&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;Mixin me, Mixin me not...So which do I use?&lt;/h2&gt;

&lt;p&gt;Ultimately, the decision will differ on a case by case basis. We can think of
it in terms of inheritance vs composition.&lt;/p&gt;

&lt;p&gt;A base class can usually live on its own or be extended. Inheriting from a parent
object will provide the child with the full functionality of the parent, plus any
additional properties and behavior that are specific to the child. &lt;em&gt;The child should
behave like the parent&lt;/em&gt;. Extending works well when you need several variations of
a parent object. Take a form, for example. You may have differing templates,
but will have mostly the same component logic. Extending each component from a base
class would make sense, and their own component-specific properties would be
defined in the new subclass.&lt;/p&gt;

&lt;p&gt;The thing about mixins is that they encapsulate succint pieces of
functionality. The code that they contain can be reused throughout different
parts of the application, and is not a concern of any one route, controller,
component, etc. They&amp;#39;re also meant to be used with other objects, not as
a stand alone piece; they don&amp;#39;t get instantiated until you&amp;#39;ve passed them
into an object, and they get created in the order of which they&amp;#39;re passed in.
Mixins can help to avoid long chains of inheritance and adds flexibility if the
need for making changes arises.&lt;/p&gt;

&lt;h3&gt;Mixin example, plz&lt;/h3&gt;

&lt;p&gt;A good candidate for a mixin? Pagination! Pagination logic is not very
extensive and it can be sprinkled throughout an application. Applications
tend to need pagination for displaying a number of things; a mixin provides
us with the ability to add this to different routes, without caring about
the type of model or object that we&amp;#39;re trying to display on the page.
Let&amp;#39;s say we have the following routes:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Router.extend({
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;authors&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;blog&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;All of these routes need to have pagination built-in. Even though the routes
are not related, we can utilize the same pagination mixin for all of them. Each
of these three routes will have to include the mixin like so:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; PaginationMixin from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../mixins/pagination&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Route.extend(PaginationMixin);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Extend example, plz&lt;/h3&gt;

&lt;p&gt;A good candidate for extension? Authentication! More often than not, we need two
different types of routes: authenticated and unauthenticated. The best way to
handle this is to create a base class for each of those (or just one,
depending on your needs!), and extend the routes which need the particular
functionality. If we have the following routes,&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Router.extend({
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;blog&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// routes/authenticated.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  &lt;span class=&quot;comment&quot;&gt;// check for session &amp;amp; transition accordingly&lt;/span&gt;
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;in &lt;code&gt;account/index.js&lt;/code&gt; we would just extend &lt;code&gt;authenticated.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// account/index.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; AuthenticatedRoute from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;routes/authenticated&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; AuthenticatedRoute.extend();
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Doing this will make sure that &lt;code&gt;account&lt;/code&gt; and any child route is off limits to
users who are not signed in. We simply apply this same pattern to any other
parent routes that need authentication. If we were to use a mixin instead, we
would end up with having to import the mixin all over the application - and
you&amp;#39;re more likely to forget to add it.&lt;/p&gt;

&lt;h2&gt;Sum it up!&lt;/h2&gt;

&lt;p&gt;Hopefully this has helped in better understanding the differences between using
&lt;code&gt;Ember.Object.extend()&lt;/code&gt; and &lt;code&gt;Ember.Mixin&lt;/code&gt; as it&amp;#39;s not always black or white on
whether to use one concept over the other. Ask yourself what the intent of the code is,
where and how often it&amp;#39;s going to be used, and make your best judgement. All
in all, stay DRY!&lt;/p&gt;
</content>
  </entry><entry>
    <title>CSS Dev Conference 2015 Thoughts</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/11/05/CSSDevConf-2015-thoughts" />
    <id>https://dockyard.com/blog/2015/11/05/CSSDevConf-2015-thoughts</id>
    <category term="html" label="Html"/><category term="css" label="Css"/><category term="conference" label="Conference"/>
    <published>2015-11-05 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Cory Tanner</name></author>
    <summary>Brief thoughts on my experience at CSS Dev Conference and all my notes</summary>
    <content type="html">&lt;p&gt;As a UX Developer I specialize in HTML/CSS so a CSS developer conference could not have been any more perfect. Three DockYarders, including myself, had the opportunity to go to &lt;a href=&quot;http://2015.cssdevconf.com/&quot;&gt;CSS Dev Conf&lt;/a&gt; last week aboard the Queen Mary in LA.&lt;/p&gt;

&lt;p&gt;The talks went beyond my expectations and I learned something different at each one. Even with new content being presented it was good to see that the tools and opinions of the speakers were all aligned with how we structure HTML/CSS at DockYard.&lt;/p&gt;

&lt;p&gt;The most interesting event at the conference was the open question session at the end of day 2. All the speakers got on stage at once and the audience could go to a microphone in the middle of the room and ask the group any question that came to mind. There were some great insights shared about what CSS developers should expect to see from the job market and what the future of CSS will look like.&lt;/p&gt;

&lt;p&gt;The Queen Mary was amazing to stay on throughout the conference and I have to give a shoutout to left shark, right shark and the giant octopus at the after party. Could not have asked for a better venue. Who wouldn&amp;#39;t want to go to a conference on a boat?!&lt;/p&gt;

&lt;p&gt;Here are my takeways from the conference!&lt;/p&gt;

&lt;h2&gt;Keynote Sara Soueidan&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/SaraSoueidan&quot;&gt;@SaraSoueidan&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://www.slideshare.net/SaraSoueidan/svg-for-web-designers-and-developers&quot;&gt;SVG For Web Designers (and Developers)&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use SVGs for everything possible and provide fallbacks for browsers that need it&lt;/li&gt;
&lt;li&gt;Keep in mind you need to look at performance, donât choose SVGs over performance&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;SVG forâ¦&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Icon systems&lt;/li&gt;
&lt;li&gt;Add banners&lt;/li&gt;
&lt;li&gt;Infographics&lt;/li&gt;
&lt;li&gt;Data visualizations&lt;/li&gt;
&lt;li&gt;Animated illustrations&lt;/li&gt;
&lt;li&gt;Filter effects&lt;/li&gt;
&lt;li&gt;Simple UI shapes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Future&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;CSS Spec custom add SVGs rules coming soon&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Designing SVGs&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Every design decision that is made while designing an SVG affects development&lt;/li&gt;
&lt;li&gt;Developers and Designers need early communication and have some give and take to make both their lives simpler&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Process&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Outline text that has been changed into vectors are not selectable&lt;/li&gt;
&lt;li&gt;Outline text preserves font-face&lt;/li&gt;
&lt;li&gt;Use simple shapes over a &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;easy to maintain&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Simplify your paths when you use them with simplify path tool in Illustrator&lt;/li&gt;
&lt;li&gt;Only combine paths if you donât need sections to be separate for animation or coloring&lt;/li&gt;
&lt;li&gt;Use organized naming/layer conventions in your SVG code&lt;/li&gt;
&lt;li&gt;Designers should use SVGs filters that are available in Illustrator effects section&lt;/li&gt;
&lt;li&gt;Always keep &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes on the &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Great for fallback&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Optimize&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Most popular tool is SVGO but will change the structure of the SVG, also can break your SVGs :( so use the GUI version with custom options&lt;/li&gt;
&lt;li&gt;Optimizing your SVG can cut your files size by half&lt;/li&gt;
&lt;li&gt;Illustrator in the future will have optimize options&lt;/li&gt;
&lt;li&gt;Sketch has no options yet :(&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Development&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Multiple &lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt; elements being combined into one SVG, always include &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; for accessibility&lt;/li&gt;
&lt;li&gt;This technique puts the SVGs code in a shadow DOM that is difficult to style&lt;/li&gt;
&lt;li&gt;You can leak styles in with CSS variables &lt;code&gt;var(--prime-color)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Use SVGs &lt;code&gt;viewbox&lt;/code&gt; to create a view window that only shows a portion of the SVGs file. Also known as the sprite technique

&lt;ul&gt;
&lt;li&gt;Place your SVG files into the CSS as background-images&lt;/li&gt;
&lt;li&gt;support back to IE6&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Use CSS only for simple animations&lt;/li&gt;
&lt;li&gt;Use JS for complex animations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;SVG over icon fonts&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Infinite scale and easy styling&lt;/li&gt;
&lt;li&gt;Browser content blockers will block fonts and not SVGs&lt;/li&gt;
&lt;li&gt;Tools for switching from icon-fonts to SVG are out there.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://greensock.com/get-started-js&quot;&gt;Greensock&lt;/a&gt; animation library is a go-to&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;object&amp;gt;&lt;/code&gt; is most flexible embedding technique for SVG&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Cracking the SVG Code: Brenda Storer&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/brendamarienyc&quot;&gt;@brendamarienyc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://brendastorer.com/presentations/2015-10-CSSDevConf-SVGs/#intro&quot;&gt;Cracking the SVG Code&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Queen Mary is in the top 10 most haunted places in the world. Over 150 spirits on the boat&lt;/li&gt;
&lt;li&gt;Whats inside a SVG? XML!

&lt;ul&gt;
&lt;li&gt;It&amp;#39;s like HTML but for digital drawings instead of content&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;SVG 1.0 became recommended in 2001 by W3C&lt;/li&gt;
&lt;li&gt;SVG 2.0 maybe in 2018 :)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;viewBox&lt;/code&gt; defaults to px if no value is given&lt;/li&gt;
&lt;li&gt;&lt;code&gt;viewBox=&amp;quot;0 0 100 100&amp;quot;&lt;/code&gt; start x start y end x end y&lt;/li&gt;
&lt;li&gt;For inline SVG remove all unneeded markup that is inserted by Illustrator&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;g&amp;gt;&lt;/code&gt; is the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; of SVGs&lt;/li&gt;
&lt;li&gt;Stroke = CSS border and fill = CSS background-color&lt;/li&gt;
&lt;li&gt;GO Shapes! &lt;code&gt;&amp;lt;rect&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;circle&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ellipse&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;line&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;polyline&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;polygon&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In Illustrator you can select what you want to be a SVG and then shorthand copy it, then paste in your text editor

&lt;ul&gt;
&lt;li&gt;This also starts your &lt;code&gt;viewBox&lt;/code&gt; at 0 0 !!!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Transforms on SVG is not 100% supported with your .css file but if you include the transform inline style its 100% supported&lt;/li&gt;
&lt;li&gt;Checkout &lt;a href=&quot;http://www.amazon.com/jQuery-Compressed-Jakob-Jenkov-ebook/dp/B006DI6QJ2/ref=asap_bc?ie=UTF8&quot;&gt;SVG Compressed&lt;/a&gt; book online&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Creative Typography with SVG: Brenna OâBrien&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;http://twitter.com/brnnbrn&quot;&gt;@brnnbrn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://talks.brennaobrien.com/svg-typography/#/&quot;&gt;Creative Typography With SVG&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VREAM - viewBox Rules Everything Around Me&lt;/li&gt;
&lt;li&gt;SVG easy to manipulate with CSS and JS&lt;/li&gt;
&lt;li&gt;Text becomes completely responsive when inside a SVG&lt;/li&gt;
&lt;li&gt;Go on a code adventure with SVG you will find new things&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;SVG has a &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt; element&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt; is accessible!

&lt;ul&gt;
&lt;li&gt;Inherits font-family from &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use fill to change color&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y=&amp;quot;0&amp;quot;&lt;/code&gt;is not good, use &lt;code&gt;y=â1emâ&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-size=&amp;quot;80&amp;quot;&lt;/code&gt; is 80px&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;&lt;code&gt;&amp;lt;tspan&amp;gt;&lt;/code&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;similar to &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; for positioning&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Curved text&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;&amp;lt;textPath&amp;gt;&lt;/code&gt; and then link it to a &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; that is inside your &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; with a &lt;code&gt;xlink:href=&amp;quot;pathName&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Gradients on text&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;linearGradient&amp;gt;&lt;/code&gt; in your &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In your &lt;code&gt;fill&lt;/code&gt; on the &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt; use &lt;code&gt;fill=âurl(#grad)â&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Images on text&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Can put your &lt;code&gt;&amp;lt;image&amp;gt;&lt;/code&gt; inside a &lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt; under your &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt; and apply the pattern to the fill on your &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;You can also fill text with gifs :)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Knockout text&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Place your &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt; in a &lt;code&gt;&amp;lt;mask&amp;gt;&lt;/code&gt; and then apply the mask to your element you want the text to be in as &lt;code&gt;mask=&amp;quot;url(#knockoutText)&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Self Typing Text&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt; as a child of what element is being animated with &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;to&lt;/code&gt; with a &lt;code&gt;duration&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Morph Text Glyphs&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Convert your text to paths with Illustrator outlines&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Self drawing text&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;stroke-dasharray&lt;/code&gt; and &lt;code&gt;stroke-dashoffset&lt;/code&gt; are used to âhackâ this effect&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Designing Complex SVG Animations: Sarah Drasner&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;http://twitter.com/sarah_edo&quot;&gt;@sarah_edo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://slides.com/sdrasner/cssdevconf#/&quot;&gt;Designing Complex SVG Animations&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why make complex animations?

&lt;ul&gt;
&lt;li&gt;powerful to convey meaning&lt;/li&gt;
&lt;li&gt;fun :)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Animation should be designed and not an afterthought or it will look like sugar on top animations&lt;/li&gt;
&lt;li&gt;One size does not fit all, look at your website and limitations&lt;/li&gt;
&lt;li&gt;Checkout Val Headâs â&lt;a href=&quot;http://valhead.com/category/all-the-right-moves-screencast/&quot;&gt;All the Right Moves&lt;/a&gt;â&lt;/li&gt;
&lt;li&gt;When designing complex animations try to design everything first and then apply the animations&lt;/li&gt;
&lt;li&gt;Ugly storyboards save you time (even if ther&amp;#39;re ugly)!&lt;/li&gt;
&lt;li&gt;SVG has less HTTP requests&lt;/li&gt;
&lt;li&gt;Optimize your SVGs!&lt;/li&gt;
&lt;li&gt;But donât overdo the amount of animations you include on your website, simplicity is key&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;UI/UX Animation&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This is used to enhance the information on the page&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Context-Shifting&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This removes the breakpoints of information being loaded on the page&lt;/li&gt;
&lt;li&gt;Use animation to fill time while loading to keep the users mind at ease&lt;/li&gt;
&lt;li&gt;Provide clear focus on what the user should be reading or looking at&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Standalone&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Questions to ask

&lt;ul&gt;
&lt;li&gt;Responsive?&lt;/li&gt;
&lt;li&gt;toggle on/off?&lt;/li&gt;
&lt;li&gt;Easing structures&lt;/li&gt;
&lt;li&gt;User flow&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Easing can contribute to your branding

&lt;ul&gt;
&lt;li&gt;You can convey emotion with how you animate elements&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Animation branding guidelines make communication down the line easy&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Animation performance&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test everything yourself&lt;/li&gt;
&lt;li&gt;People expect everything to be faster on the web&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;SVG sprites complex to simple&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Design your three steps for desktop, tablet, and mobile&lt;/li&gt;
&lt;li&gt;Combine elements where you can so you have less SVGs elements you need to hide when going between views&lt;/li&gt;
&lt;li&gt;Use animation media queries&lt;/li&gt;
&lt;li&gt;&lt;code&gt;viewBox&lt;/code&gt; shift with JS&lt;/li&gt;
&lt;li&gt;provide fallbacks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Complex animations&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use JS to make this easy&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&quot;http://greensock.com/get-started-js&quot;&gt;Greensock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you need more then 2-3 chained events in your animation its a good idea to use JS&lt;/li&gt;
&lt;li&gt;Relative color tweening

&lt;ul&gt;
&lt;li&gt;Example: shifting from day to night scenes&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Motion along a path is important for realism&lt;/li&gt;
&lt;li&gt;Responsive animations should be made with thought as you place the elements in DOM&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Design + Animation + Data&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Combining these things can bring back the success of static infographics used to have&lt;/li&gt;
&lt;li&gt;We can make them responsive and interactive with SVG&lt;/li&gt;
&lt;li&gt;Add accessibility with &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; tags&lt;/li&gt;
&lt;li&gt;Go &lt;a href=&quot;http://codepen.io/&quot;&gt;CodePen&lt;/a&gt;! Easy to learn new things when you can dive into other peoples code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The Dark Arts of Light Speed: Henri Helvetica&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/HenriHelvetica&quot;&gt;@HenriHelvetica&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://www.slideshare.net/HenriHelvetica/?mc_cid=cf53aad878&amp;amp;mc_eid=60d40ffbe3&quot;&gt;The Dark Arts of Light Speed&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web performance = speed&lt;/li&gt;
&lt;li&gt;Font-end development suffers from the embarrassment of riches&lt;/li&gt;
&lt;li&gt;57% of visiters will abandon a page after 3 seconds of not loading&lt;/li&gt;
&lt;li&gt;User experience metrics over network-based metrics&lt;/li&gt;
&lt;li&gt;Need a culture based on building apps for performance&lt;/li&gt;
&lt;li&gt;Placing &lt;code&gt;defer&lt;/code&gt; in your &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag will download JS at the same time as HTML but execute JS at the end of the HTML loading

&lt;ul&gt;
&lt;li&gt;async will download JS and load HTML at the same time but pause the loading of HTML when the JS download finishes to execute it&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Donât send larger images to mobile when you donât have to, it waists bandwidth on phones&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;srcset&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; you can use media queries inside them to load images for specific VW&lt;/li&gt;
&lt;li&gt;Reduce the number of HTTP requests with combining .css files into one and .js files into one&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;No Pain No Gain: Stacy Kvernmo&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/funstacy&quot;&gt;@funstacy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://www.slideshare.net/Funstacy/no-pain-no-gain-css-code-reviews-ftw&quot;&gt;No Pain No Gain&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a culture of code review in your workplace

&lt;ul&gt;
&lt;li&gt;Catch bugs&lt;/li&gt;
&lt;li&gt;Increase familiarity of the project with your team&lt;/li&gt;
&lt;li&gt;Education! communication with your team on why you did what you did will tach you to explain things simply&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Review the compiled code when you use pre-processors&lt;/li&gt;
&lt;li&gt;Contributing to open source is great and try to repay the contributor somehow&lt;/li&gt;
&lt;li&gt;Stay positive during code reviews&lt;/li&gt;
&lt;li&gt;Avoid absolute terms when commenting

&lt;ul&gt;
&lt;li&gt;Must&lt;/li&gt;
&lt;li&gt;Always&lt;/li&gt;
&lt;li&gt;Never&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Ask questions about why the person coded a certain way&lt;/li&gt;
&lt;li&gt;Document the issues you find&lt;/li&gt;
&lt;li&gt;Document your code with comments&lt;/li&gt;
&lt;li&gt;A pull request should say what you did very clearly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;What to review&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Follow standards&lt;/li&gt;
&lt;li&gt;Is the code easy to understand&lt;/li&gt;
&lt;li&gt;Donât need to nest everything, donât go as far as 3-4 levels deep&lt;/li&gt;
&lt;li&gt;Accessibility&lt;/li&gt;
&lt;li&gt;Using correct vendor prefixes?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Keynote Jina Bolton&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/jina&quot;&gt;@jina&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;https://speakerdeck.com/jina/designing-a-design-system&quot;&gt;Designing a Design System&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Communication between Designers and Developers is important&lt;/li&gt;
&lt;li&gt;designing systems rather then pages&lt;/li&gt;
&lt;li&gt;style guides should be living and constantly updated&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://designprinciplesftw.com&quot;&gt;designprinciplesftw.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Donât make things until you need it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;v2mom&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;vision&lt;/li&gt;
&lt;li&gt;values&lt;/li&gt;
&lt;li&gt;methods&lt;/li&gt;
&lt;li&gt;obstacles&lt;/li&gt;
&lt;li&gt;measures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Keynote Val Head&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/vlh&quot;&gt;@vlh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://www.slideshare.net/valhead/designing-meaningful-animation&quot;&gt;Designing Meaningful Animation&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With new tools we have the ability to make accessible responsive and beautiful animations for the web!&lt;/li&gt;
&lt;li&gt;Using motion in our design language is important&lt;/li&gt;
&lt;li&gt;When you have motion across all platforms it provides a more recognizable interface for the user&lt;/li&gt;
&lt;li&gt;Be subtle with movements, a little will go a long way&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;CSS Architecture: Jonathan Snook&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/snookca&quot;&gt;@snookca&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://environmentsforhumans.com/2015/css-dev-conf/presentations/Snook-CSSDevConf2015-CSSArchitecture.pdf?mc_cid=cf53aad878&amp;amp;mc_eid=60d40ffbe3&quot;&gt;CSS Architecture&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build modular systems&lt;/li&gt;
&lt;li&gt;INLINE STYLES WON&amp;#39;T SAVE YOU FROM INHERITANCE&lt;/li&gt;
&lt;li&gt;Donât write multiple of the same rule for one element&lt;/li&gt;
&lt;li&gt;Future we can us &lt;code&gt;all: inherit&lt;/code&gt; on an element to ignore all inherited styles&lt;/li&gt;
&lt;li&gt;Element queries can be used but you need JS to accomplish this&lt;/li&gt;
&lt;li&gt;Design has a cost on the web just like it does in print&lt;/li&gt;
&lt;li&gt;Every peace of design ends up in code&lt;/li&gt;
&lt;li&gt;You can use emojis as class names :P&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Categorization of styles&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;state&lt;/li&gt;
&lt;li&gt;Theme&lt;/li&gt;
&lt;li&gt;module&lt;/li&gt;
&lt;li&gt;layout&lt;/li&gt;
&lt;li&gt;base&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Naming conventions&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use them!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://smacss.com/&quot;&gt;SMACSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/&quot;&gt;BEM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The goal is to isolate an element from everything else on the page&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Create Standards For Your CSS&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Without standards and code reviewing, CSS will get out of control&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://styleguides.io&quot;&gt;Styleguides.io&lt;/a&gt; is a great resource&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Future&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Web components&lt;/li&gt;
&lt;li&gt;Composable UIs&lt;/li&gt;
&lt;li&gt;Communicate!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Bower Power! Supercharging Front-End Manageability: Eric Carlisle&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/eric_carlisle&quot;&gt;@eric_carlisle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;http://www.slideshare.net/ericcarlisle/bower-power-54549427&quot;&gt;Bower Power! Supercharging Front-End Manageability&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep It Stunningly Simple (KISS)&lt;/li&gt;
&lt;li&gt;You get a happy team&lt;/li&gt;
&lt;li&gt;Better products, process, reduce cost&lt;/li&gt;
&lt;li&gt;Donât be afraid to use npm and bower&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Bower keeps it simple&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Maintains a dependency manifest&lt;/li&gt;
&lt;li&gt;Fetches them when you need it&lt;/li&gt;
&lt;li&gt;Tracks dependencies&lt;/li&gt;
&lt;li&gt;Integrates with everything&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;You need&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js Javascript runtime&lt;/li&gt;
&lt;li&gt;npm, Node.js package manager&lt;/li&gt;
&lt;li&gt;git, version control&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Starting the awesome&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm install -g bower&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bower init&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Installing dependencies&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bower install dependenciesName&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;add a &lt;code&gt;--save&lt;/code&gt; after install to save that dependency for the project&lt;/li&gt;
&lt;li&gt;add a &lt;code&gt;--save-dev&lt;/code&gt; after install to save that dependency for development or debugging&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;bower_components&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt;!!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Fight the Zombie Pattern Library: Marcelo Somers&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/marcelosomers&quot;&gt;@marcelosomers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;https://speakerdeck.com/marcelosomers/fight-the-zombie-pattern-library-css-dev-conf-2015&quot;&gt;Fight the Zombie Pattern Library&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;âHow do you keep building interfaces knowing thats what the world is likeâ&lt;/li&gt;
&lt;li&gt;Pattern library accelerate both the design process and development process&lt;/li&gt;
&lt;li&gt;Photoshop has libraries that you can make/use in multiple files/projects

&lt;ul&gt;
&lt;li&gt;You can do this in teams also&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Traditional handoff between designers and developers is broken&lt;/li&gt;
&lt;li&gt;Use pattern libraries as the connection between the groups&lt;/li&gt;
&lt;li&gt;Libraries eliminate waste&lt;/li&gt;
&lt;li&gt;This reduces tweaking static comps to make one small change but rather make one change to an item in a library&lt;/li&gt;
&lt;li&gt;You want an automated library or a team managing your libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Get started today&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Take an inventory&lt;/li&gt;
&lt;li&gt;Take documentation

&lt;ul&gt;
&lt;li&gt;Base styles&lt;/li&gt;
&lt;li&gt;Components&lt;/li&gt;
&lt;li&gt;Page templates&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Focus on standardizing what you find&lt;/li&gt;
&lt;li&gt;Define CSS standards

&lt;ul&gt;
&lt;li&gt;Refactor to perfection&lt;/li&gt;
&lt;li&gt;Namespace the CSS&lt;/li&gt;
&lt;li&gt;Donât forget about JavaScript applying classes&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Govern your library&lt;/li&gt;
&lt;li&gt;Open source culture

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://opencss.klamp.in&quot;&gt;opencss.klamp.in&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Pattern Library Tools&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Writing CSS documentation with &lt;a href=&quot;http://warpspire.com/kss/&quot;&gt;KSS&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;will auto document comments in your &lt;code&gt;.css&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Pattern lab on GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;The better way&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/patternpack/patternpack&quot;&gt;patternpack&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;what it does&lt;/li&gt;
&lt;li&gt;Build your static site&lt;/li&gt;
&lt;li&gt;Increment your version&lt;/li&gt;
&lt;li&gt;Create a new commit&lt;/li&gt;
&lt;li&gt;Tag the commit&lt;/li&gt;
&lt;li&gt;Lets you share the code to multiple applications&lt;/li&gt;
&lt;li&gt;Keeps versions of the design&lt;/li&gt;
&lt;li&gt;Start new project with &lt;code&gt;npm init&lt;/code&gt; and &lt;code&gt;git init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;npm install --save-dev pattern-pack&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Start with &lt;code&gt;grunt patternpack run&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create your first patter with a &lt;code&gt;.md&lt;/code&gt; and &lt;code&gt;.css&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt; &lt;code&gt;.md&lt;/code&gt; is the documentation for the equivalent &lt;code&gt;css&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Use semantic versioning for your pattern pack&lt;/li&gt;
&lt;li&gt;Publish your patternpack&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grunt pattern pack:release&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push âfollow-tags&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Web Components and the Future of Modular CSS: Philip Walton&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/philwalton&quot;&gt;@philwalton&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;https://philipwalton.github.io/talks/2015-10-26/#1&quot;&gt;Web Components And the future of Modular CSS&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Good news is that web components were primarily a google effort but not all vendors are on board but could be available sometime in 2016&lt;/li&gt;
&lt;li&gt;Your selectors are the biggest determining factor in how scalable your code is&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Whats changed?&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multiple shadow roots have gone away&lt;/li&gt;
&lt;li&gt;&lt;code&gt;createShadowRoot()&lt;/code&gt; is now &lt;code&gt;attachShadow(mode)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;CSS is hard&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Manage global names&lt;/li&gt;
&lt;li&gt;Scoping/isolating styles&lt;/li&gt;
&lt;li&gt;Specificity conflicts&lt;/li&gt;
&lt;li&gt;Unpredictable matching&lt;/li&gt;
&lt;li&gt;Managing styles dependencies&lt;/li&gt;
&lt;li&gt;Removing unused code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;What is CSS missing&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Scope or isolate styles to a particular set of DOM nodes&lt;/li&gt;
&lt;li&gt;Ability to abstract away implementation details&lt;/li&gt;
&lt;li&gt;Goooo Web components! They do this&lt;/li&gt;
&lt;li&gt;You donât want to have to depend on tools that everyone has to learn&lt;/li&gt;
&lt;li&gt;No ecosystems&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;The Anatomy of a Web Component&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Elements in a shadow DOM

&lt;ul&gt;
&lt;li&gt;Its a subtree of a DOM node that canât be styled by CSS&lt;/li&gt;
&lt;li&gt;Shadow nodes are private&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Custom elements&lt;/li&gt;
&lt;li&gt;HTMl imports&lt;/li&gt;
&lt;li&gt;The template element&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Keynote Dave Rupert&lt;/h2&gt;

&lt;p&gt;Twitter: &lt;a href=&quot;https://twitter.com/davatron5000&quot;&gt;@davatron5000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slides: &lt;a href=&quot;https://speakerdeck.com/davatron5000/the-art-of-being-wrong&quot;&gt;The Art Of Being Wrong&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Woot &lt;a href=&quot;http://shoptalkshow.com/&quot;&gt;Shop Talk show&lt;/a&gt; plug&lt;/li&gt;
&lt;li&gt;Working on &lt;a href=&quot;http://godaytrip.com&quot;&gt;godaytrip.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Remove the must doâs and âfactsâ from statements online on twitter or medium&lt;/li&gt;
&lt;li&gt;what you think you know about dinosaurs is WRONG!&lt;/li&gt;
&lt;li&gt;Be afraid of the Donald Trump effect where you believe bullshit if it is said loud and long enough&lt;/li&gt;
&lt;li&gt;Donât spell Sass or SASS wrong or the internet will bring the pitchforks, aka people should not fight about every little thing on the web&lt;/li&gt;
&lt;li&gt;You donât have to be right all the time and you donât have to correct people on everything all the time&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry><entry>
    <title>Data visualization workshop</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/11/03/data-visualization-workshop" />
    <id>https://dockyard.com/blog/2015/11/03/data-visualization-workshop</id>
    <category term="data-visualization" label="Data Visualization"/><category term="user-experience" label="User Experience"/>
    <published>2015-11-03 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Ashley Treni</name></author>
    <summary>Our next UX East hands-on workshop</summary>
    <content type="html">&lt;p&gt;Iâm very excited to host UX East&amp;#39;s next workshop on &lt;a href=&quot;http://www.meetup.com/UX-East/events/226344211/&quot;&gt;data visualization&lt;/a&gt; here at DockYard! I received my Masterâs degree earlier this year from Northeasternâs &lt;a href=&quot;http://www.northeastern.edu/camd/artdesign/academic-programs/mfa-in-information-design-and-visualization/&quot;&gt;Information Design and Visualization&lt;/a&gt; program, and data visualization is one of my favorite things to geek out about. &lt;/p&gt;

&lt;p&gt;There are many interesting parallels between UX design thinking and the process around creating data visualizations. This workshop will be a comprehensive overview of that process, with a special focus on context and experience. Together, weâll explore a dataset (a very interesting one!), create a story around a target audience, use the data to define appropriate visualization methods, and storyboard the experience.&lt;/p&gt;

&lt;p&gt;Creatives and makers of all types and skill levels are encouraged to come. During this workshop, weâll manually look through the data and sketch our explorations. No background in engineering or design is needed, but we can  discuss digital visualization tools for those who are interested. Itâll be a very fun collaborative evening. &lt;/p&gt;

&lt;p&gt;To give you a taste of some of the examples to come - here are a few of my favorite data visualizations that create very different experiences. Many more will be included in the pre-workshop presentation about data visualization basics and best practices.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Jsk6FWh.jpg&quot; alt=&quot;SoSoLimited&quot;&gt;
&lt;em&gt;âCSIS data chandelierâ - &lt;a href=&quot;http://www.sosolimited.com/work/csis-data-chandelier/&quot;&gt;SoSoLimited&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/cRZM0lH.png&quot; alt=&quot;Bloomberg&quot;&gt;
&lt;em&gt;âWhatâs really warming the world?â - &lt;a href=&quot;http://www.bloomberg.com/graphics/2015-whats-warming-the-world/&quot;&gt;Bloomberg&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/8ZR8Y50.png&quot; alt=&quot;Dear Data&quot;&gt;
&lt;em&gt;&lt;a href=&quot;http://www.dear-data.com/&quot;&gt;Dear Data&lt;/a&gt; - Stephanie Posavec and Giorgia Lupi&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Come make with us! If you have any questions about the workshop, please feel free to &lt;a href=&quot;mailto:ashley.treni@dockyard.com&quot;&gt;email me&lt;/a&gt;. Hope to see you there!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Stop bubbling actions and use closure actions</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/29/ember-best-practice-stop-bubbling-and-use-closure-actions" />
    <id>https://dockyard.com/blog/2015/10/29/ember-best-practice-stop-bubbling-and-use-closure-actions</id>
    <category term="best-practices" label="Best Practices"/><category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/>
    <published>2015-10-29 00:00:00</published>
    <updated>2016-04-29 00:20:49</updated>
    <author><name>Dan McClain</name></author>
    <summary>Bubbling no longer required</summary>
    <content type="html">&lt;p&gt;Back in January, I talked about &lt;a href=&quot;https://dockyard.com/blog/2015/01/28/bubbling-actions-through-components&quot;&gt;bubbling actions through components&lt;/a&gt;
so that you could nest components and have an action be triggered from the
depths of your inner component. This involved passing actions down through your
components, and then using &lt;code&gt;sendAction&lt;/code&gt; to trigger the action at each level
until you got all the way out of your nesting. With the introduction of
&lt;a href=&quot;http://emberjs.com/blog/2015/06/12/ember-1-13-0-released.html#toc_closure-actions&quot;&gt;closure actions&lt;/a&gt;, you end up passing actions down, but no longer have
to bubble out.&lt;/p&gt;

&lt;h2&gt;Actions down&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s look at the example from the previous blog post again:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! index.hbs}}
  {{pressCount}} Button presses
  {{button-wrapper action=&amp;quot;buttonClick&amp;quot;}}

{{! components/button-wrapper.hbs}}
  &amp;lt;h2&amp;gt;Button Wrapper&amp;lt;/h2&amp;gt;
  {{press-button action=&amp;quot;buttonClick&amp;quot;}}

{{! components/press-button.hbs}}
  &amp;lt;button {{action &amp;quot;buttonClick&amp;quot;}}&amp;gt;My Button&amp;lt;/button&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice how we we are using the &lt;code&gt;action=&amp;quot;buttonClick&amp;quot;&lt;/code&gt; above the &lt;code&gt;press-button&lt;/code&gt;
component to pass the action down. We end up calling &lt;code&gt;this.sendAction()&lt;/code&gt; in
both components so that the button 2 levels deep calls the action defined in
the index controller.&lt;/p&gt;

&lt;p&gt;What if I told you that you only need to define the templates for the
components, and no longer need to have any actions defined within the
components themselves?&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! index.hbs}}
  {{pressCount}} Button presses
  {{button-wrapper click=(action &amp;quot;buttonClick&amp;quot;)}}

{{! components/button-wrapper.hbs}}
  &amp;lt;h2&amp;gt;Button Wrapper&amp;lt;/h2&amp;gt;
  {{press-button click=(action click)}}

{{! components/press-button.hbs}}
  &amp;lt;button {{action (action click)}}&amp;gt;My Button&amp;lt;/button&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Closure actions are called by using the &lt;code&gt;action&lt;/code&gt; helper, which in turn
passes down the function to the component, defining it at &lt;code&gt;&amp;lt;property
name&amp;gt;&lt;/code&gt;, just like other properties passed to your component.At the
bottom, the &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; action just calls the action, and the controller
action is the same as before. &lt;a href=&quot;http://jsbin.com/logawi/1/edit?html,js,output&quot;&gt;You can see it in action
here&lt;/a&gt;. There is no code backing the component at this
point.&lt;/p&gt;

&lt;h2&gt;Ok, what if I wanted to do something a bit more complicated&lt;/h2&gt;

&lt;p&gt;This is where closure actions really show off. With closure actions, you can
have the function you pass in to the action &lt;em&gt;return a value&lt;/em&gt;. This was
previously impossible because the return value of a function was used to
determine if the action should bubble. This also highlights one of the
potential gotchas you may encounter when you first start using closure actions:
they don&amp;#39;t bubble. If you use a closure action, it won&amp;#39;t bubble out of the
controller/component. If you need this behavior, you need to call &lt;code&gt;this.send&lt;/code&gt;
in the controller to fire an action that will be triggered in your route. &lt;a href=&quot;http://jsbin.com/logawi/2/edit?html,js,output&quot;&gt;Here
is an example&lt;/a&gt;. Note that the name of the action sent is
different than the action called, you&amp;#39;ll end up in an infinite loop if you try
to &lt;code&gt;this.send(&amp;#39;buttonClick&amp;#39;)&lt;/code&gt;. When routeable components land, you&amp;#39;ll likely
end up passing the route action into the component using closure actions, so
unless you really need route actions with closure actions, I would recommend
against leaning on this example.&lt;/p&gt;

&lt;h2&gt;Can you do anything cool with closure actions?&lt;/h2&gt;

&lt;p&gt;Yes, you can now &lt;a href=&quot;https://en.wikipedia.org/wiki/Currying&quot;&gt;curry&lt;/a&gt;! You can pass multiple arguments to the &lt;code&gt;action&lt;/code&gt; helper
at each level. Those arguments are added to the function at each scope. Let&amp;#39;s
look at a bit of code to make this clearer:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! index}}
    Things: {{things}}
    {{cat-wrapper class=&amp;quot;button-wrapper&amp;quot; click=(action &amp;quot;buttonClick&amp;quot;)}}
    {{dog-wrapper class=&amp;quot;button-wrapper&amp;quot; click=(action &amp;quot;buttonClick&amp;quot;)}}

{{! components/cat-wrapper.hbs}}
    &amp;lt;h2&amp;gt;Cats&amp;lt;/h2&amp;gt;
    {{press-button count=1 class=&amp;quot;press-button&amp;quot; click=(action click &amp;quot;cat&amp;quot;)}}
    {{press-button count=2 class=&amp;quot;press-button&amp;quot; click=(action click &amp;quot;cats&amp;quot;)}}

{{! components/dog-wrapper.hbs}}
  &amp;lt;h2&amp;gt;Dogs&amp;lt;/h2&amp;gt;
  {{press-button count=1 class=&amp;quot;press-button&amp;quot; click=(action click &amp;quot;dog&amp;quot;)}}
  {{press-button count=2 class=&amp;quot;press-button&amp;quot; click=(action click &amp;quot;dogs&amp;quot;)}}

{{! components/press-button.hbs}}
  &amp;lt;button {{action (action click count)}}&amp;gt;{{count}}&amp;lt;/button&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice how we pass &lt;code&gt;cat/cats/dog/dogs&lt;/code&gt; to the &lt;code&gt;action&lt;/code&gt; of each &lt;code&gt;press-button&lt;/code&gt;
in the &lt;code&gt;cat-wrapper&lt;/code&gt; and &lt;code&gt;dog-wrapper&lt;/code&gt; component, but in the &lt;code&gt;press-button&lt;/code&gt;
component, we just pass the count to the &lt;code&gt;action&lt;/code&gt; helper after passing it the
function we want to call. The function that is called in &lt;code&gt;press-button&lt;/code&gt; has the
signature &lt;code&gt;function(thing, count)&lt;/code&gt;, so if we click the first cat button, the
&lt;code&gt;buttonClick&lt;/code&gt; action in the controller is called with &lt;code&gt;&amp;#39;cat&amp;#39;&lt;/code&gt; as the first
argument, and &lt;code&gt;count&lt;/code&gt; as the second argument. &lt;a href=&quot;http://jsbin.com/logawi/3/edit?html,js,output&quot;&gt;Here is a living version of
this example&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;What if I don&amp;#39;t use the action helper in my deepest component?&lt;/h2&gt;

&lt;p&gt;All the examples so far use the &lt;code&gt;action&lt;/code&gt; helper in &lt;code&gt;press-button&lt;/code&gt;, but if you
wanted to call your action manually, you&amp;#39;d just call &lt;code&gt;click()&lt;/code&gt; to
call the function passed into the component. &lt;a href=&quot;http://jsbin.com/logawi/4/edit?html,js,output&quot;&gt;Here is an updated version of the
currying example that uses an action in the &lt;code&gt;press-button&lt;/code&gt;
component&lt;/a&gt;. We still pass the argument to the curried function.&lt;/p&gt;

&lt;h2&gt;Functions Down, Actions up&lt;/h2&gt;

&lt;p&gt;With the introduction of closure actions in Ember 1.13, we gained a powerful way
of passing data down in the form of functions to push data up and out of our
components. This was possible before, but it was also a lot more work. You&amp;#39;d
have to manually bubble actions all the way out, but now we punch a hole down
to our deepest component and fire the action directly from there. This will
lead to easier debugging, as the &lt;code&gt;sendAction&lt;/code&gt; way was a lot harder to grok
where your component actions were breaking.&lt;/p&gt;
</content>
  </entry><entry>
    <title>How long it took to convert our team from Rails to Phoenix</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/29/how-long-it-took-our-team-to-move-from-rails-to-phoenix" />
    <id>https://dockyard.com/blog/2015/10/29/how-long-it-took-our-team-to-move-from-rails-to-phoenix</id>
    <category term="elixir" label="Elixir"/><category term="phoenix" label="Phoenix"/>
    <published>2015-10-29 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;One week.&lt;/p&gt;

&lt;p&gt;That is how long it took for our engineers, who had all (but one) worked
with &lt;a href=&quot;http://rubyonrails.org&quot;&gt;Rails&lt;/a&gt; for a few years, to be productive on a new &lt;a href=&quot;http://phoenixframework.org&quot;&gt;Phoenix&lt;/a&gt; client
project.&lt;/p&gt;

&lt;p&gt;I had assigned each of them to read Part 1 of &lt;a href=&quot;https://pragprog.com/book/elixir/programming-elixir&quot;&gt;Dave Thomas&amp;#39; Programming Elixir&lt;/a&gt;
book which was only 160 pages of material. Part 1 introduces early
&lt;a href=&quot;https://en.wikipedia.org/wiki/Functional_programming&quot;&gt;Functional Programming&lt;/a&gt; concepts and the &lt;a href=&quot;http://elixir-lang.org&quot;&gt;Elixir&lt;/a&gt; standard library. In my
mind, this is enough to make the switch.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;âIt was cool being able to contribute to a Phoenix app without prior
experience with the framework thanks to the similarity in structure
with Rails. Elixir is the biggest hurdle, but a quick read through the
key concepts is enough to make you productive - not to mention
learning a new language is fun!â&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;-- Romina Vargas, DockYard Engineer&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At the higher level of writing actions, routes, tests, models, queries, etc... there is so much
overlap with the concepts that exist in Rails that it was simply a
matter of syntax that had to be learned before a Rails engineer could
make contributions back to Phoenix applications.&lt;/p&gt;

&lt;p&gt;There is no doubt that Phoenix borrows &lt;em&gt;a lot&lt;/em&gt; of concepts and structure
from Rails. For good reason, Rails nailed the &lt;a href=&quot;http://betterexplained.com/articles/intermediate-rails-understanding-models-views-and-controllers/&quot;&gt;MVC app pattern&lt;/a&gt;. The
benefit here is that a lot of that domain knowledge on how to build
Rails apps can be transferred over to building Phoenix
apps.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;âRuby on Rails had a pretty steep learning curve. Not only did I have
to study a new programming language, I had to master the MVC framework
as well. But with RoR under my belt, the learning curve for Elixir and
Phoenix was significantly reduced. Plus pattern matching makes
everything way easier!â&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;-- Marin Abernethy, DockYard Engineer&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, don&amp;#39;t get me wrong. I am not suggesting that after this one week
that you should be ramped up on the complexities of Elixir and the
Erlang ecosystem. I think there is enough to Erlang that could take
years to fully absorb. But that&amp;#39;s not the point.&lt;/p&gt;

&lt;p&gt;The best way to write a faster Rails app is to write it in
Phoenix.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dockyard.com/contact&quot;&gt;Get in touch with us if you&amp;#39;d like to move from Rails to Phoenix. We can
help!&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Validating your Ecto Models with ValidField</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/26/validating-your-ecto-models-with-valid_field" />
    <id>https://dockyard.com/blog/2015/10/26/validating-your-ecto-models-with-valid_field</id>
    <category term="phoenix" label="Phoenix"/><category term="testing" label="Testing"/><category term="elixir" label="Elixir"/>
    <published>2015-10-26 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Dan McClain</name></author>
    <summary>Unit testing your changesets made easy</summary>
    <content type="html">&lt;p&gt;When we were working with Rails, we would unit test our validations with a
libary called &lt;a href=&quot;https://github.com/bcardarella/valid_attribute&quot;&gt;ValidAttribute&lt;/a&gt;. This library would allow you to
specify the attribute and a list of values then check if the values yield
errors or not. On a recent client project, I resurrected the pattern and
extracted it as a Phoenix library this weekend.&lt;/p&gt;

&lt;h2&gt;Introducing ValidField&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s import &lt;a href=&quot;https://github.com/dockyard/valid_field&quot;&gt;ValidField&lt;/a&gt; and get right to the tests:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule App.UserTest do
  import ValidField
  use ExUnit.Case
  alias App.User

  test &amp;quot;.changeset - Validations&amp;quot; do
    with_changeset(%User{})
    |&amp;gt; assert_valid_field(:email, [&amp;quot;something@else.com&amp;quot;])
    |&amp;gt; assert_invalid_field(:email, [&amp;quot;&amp;quot;, nil, &amp;quot;test&amp;quot;])
    |&amp;gt; assert_valid_field(:password, [&amp;quot;password123!&amp;quot;])
    |&amp;gt; assert_invalid_field(:password, [nil, &amp;quot;&amp;quot;, &amp;quot;test&amp;quot;, &amp;quot;nospecialcharacters1&amp;quot;, &amp;quot;nonumber!&amp;quot;])
  end

  test &amp;quot;.changeset - Validations - complex changeset&amp;quot; do
    with_changeset(%User{}, fn (model, params) -&amp;gt; App.UserController.changeset(model, params, :insert))
    |&amp;gt; assert_valid_field(:email, [&amp;quot;something@else.com&amp;quot;])
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;First, we use &lt;code&gt;with_changeset/1&lt;/code&gt;, which takes the model struct as the sole
argument and returns a map that contains an anonymous function that yields a
changeset from &lt;code&gt;Model.changeset&lt;/code&gt;. &lt;code&gt;with_changeset/1&lt;/code&gt; assumes that your
changeset is defined at &lt;code&gt;Model.changeset/2&lt;/code&gt;. If your changeset is defined
elsewhere or has additional arguments, you&amp;#39;ll want to use &lt;code&gt;with_changeset/2&lt;/code&gt;.
The first argument of &lt;code&gt;with_changeset/2&lt;/code&gt; is still the model struct, but the
second argument is a function with an arity of 2. The first argument to the
function will be the model struct passed in, the second argument will be a map
of field values to be set in the changeset.&lt;/p&gt;

&lt;p&gt;After we have a changeset map, we pass that as the first argument to
&lt;code&gt;assert_valid_field/3&lt;/code&gt; and &lt;code&gt;assert_invalid_field/3&lt;/code&gt;. Instead of returning a
boolean of whether or not the field is valid for the list of values passed in,
these functions run the assertions internally. This is done to provide useful
testing errors when running &lt;code&gt;mix test&lt;/code&gt;. Assume that you inverted the third line
of the test to be the following (and didn&amp;#39;t change your validations), the
following error will be generated:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;defmodule App.UserTest do
  import ValidField
  use ExUnit.Case
  alias App.User

  test &amp;quot;.changeset - Validations&amp;quot; do
    with_changeset(%User{})
    |&amp;gt; assert_valid_field(:email, [&amp;quot;something@else.com&amp;quot;])
    |&amp;gt; assert_valid_field(:email, [&amp;quot;&amp;quot;, nil, &amp;quot;test&amp;quot;])
    # (ExUnit.AssertionError) Expected the following values to be valid for &amp;quot;email&amp;quot;: nil, &amp;quot;&amp;quot;, &amp;quot;tests&amp;quot;
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;OK, I see what you did there but why?&lt;/h2&gt;

&lt;h3&gt;Clean workflow for unit testing changesets&lt;/h3&gt;

&lt;p&gt;By grouping all the valid and invalid cases in your tests, you can
quickly understand what makes your changeset valid. It also allows you to
update your tests by just adding another value to either function call. Say you
want to stop accepting Gmail address as valid email address; you just add
&lt;code&gt;some-email@gmail.com&lt;/code&gt; to your &lt;code&gt;assert_invalid_field&lt;/code&gt; call for email, and
update the tests to satisfy this new requirement. We aren&amp;#39;t worried about the
error message anymore.&lt;/p&gt;

&lt;h3&gt;Less brittle tests&lt;/h3&gt;

&lt;p&gt;Most unit tests around changeset validations use the &lt;code&gt;error_on&lt;/code&gt; function and
assert that the field and a specific error message are contained in the list of
errors provided. This is a decent starting point, but has a couple of
drawbacks. The first is that your test is tied directly to the error message,
meaning that changing a validation message requires you to update your test. A
correction to a gramatical error would cause a test failure, showing how
brittle this pattern could be. What if you support multiple languages? Since
your error messages might be different for an email that contains a space or
one that doesn&amp;#39;t contain a valid domain, your tests will be more verbose since
the messages need to be matched individually.&lt;/p&gt;

&lt;p&gt;With ValidField, you are testing the behavior of your changeset,
rather than the implementation of your error messages.&lt;/p&gt;

&lt;h2&gt;Go forth and test your changeset&lt;/h2&gt;

&lt;p&gt;Making sure your changeset is properly defined is important, and ValidField
makes it much easier to unit test them. Having the list of valid and invalid
values for your field in your tests also serves a documentation of what should
be accepted for a given field as well.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Computed Properties with Dynamic Dependent Keys</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/23/ember-best-practices-dynamic-dependent-keys-for-computed-properties" />
    <id>https://dockyard.com/blog/2015/10/23/ember-best-practices-dynamic-dependent-keys-for-computed-properties</id>
    <category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/>
    <published>2015-10-23 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Michael Dupuis</name></author>
    <summary>Need to determine the dependent key for your computed property at runtime?</summary>
    <content type="html">&lt;p&gt;In Ember, computed properties allow you to declare functions as properties. More often than not, you&amp;#39;re going to have a set of dependent keys which invoke a function when their values change:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const Team = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;city&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;league&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,

  &lt;span class=&quot;key&quot;&gt;fullName&lt;/span&gt;: Ember.computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)} &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
    }
  })
});

const redSox = Team.create({
  &lt;span class=&quot;key&quot;&gt;city&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Boston&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;league&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;American&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Red Sox&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

Ember.get(redSox, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// &amp;quot;Boston Red Sox&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the example above, &lt;code&gt;fullName&lt;/code&gt; is dependent on &lt;code&gt;city&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt;, so
it watches those properties, and when either of their values change,
its &lt;code&gt;get&lt;/code&gt; function is invoked, thereby returning the updated &lt;code&gt;fullName&lt;/code&gt;
property for our beloved baseball team.&lt;/p&gt;

&lt;p&gt;What if you wanted to write a computed property that didn&amp;#39;t know what
keys it needed to monitor until runtime?&lt;/p&gt;

&lt;p&gt;In our contrived examples below, our &lt;code&gt;model&lt;/code&gt; is an array of
baseball teams which will be passed to a component.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const Team = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;city&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;league&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;
});

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  model() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; {
      &lt;span class=&quot;key&quot;&gt;teams&lt;/span&gt;: [
        Team.create({ &lt;span class=&quot;key&quot;&gt;league&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;American&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;city&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Boston&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Red Sox&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }),
        Team.create({ &lt;span class=&quot;key&quot;&gt;league&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;American&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;city&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;New York&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Yankees&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }),
        Team.create({ &lt;span class=&quot;key&quot;&gt;league&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;National&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;city&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Los Angeles&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Dodgers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }),
        Team.create({ &lt;span class=&quot;key&quot;&gt;league&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;National&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;city&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;San Francisco&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Giants&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; })
      ]
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In a component, we&amp;#39;re going to separate our American League teams and our National
League teams.&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;league-teams&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;leagueData&lt;/span&gt;=&lt;span class=&quot;attribute-value&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// league-teams/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;americanLeagueTeams&lt;/span&gt;: Ember.computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;leagueData.teams.@each.league&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      const teams = Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;leagueData.teams&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; teams.filterBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;league&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;American&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    }
  }),

  &lt;span class=&quot;key&quot;&gt;nationalLeagueTeams&lt;/span&gt;: Ember.computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;leagueData.teams.@each.league&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      const teams = Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;leagueData.teams&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; teams.filterBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;league&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;National&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    }
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We have two computed properties in our component. The first one pulls the
American League teams and the second pulls the National League teams.
The functions performing this work are virtually identical with the
exception of the value against which they are filtering (i.e.,
&amp;quot;American&amp;quot; and &amp;quot;National&amp;quot;). Let&amp;#39;s DRY
this code up a bit:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;filterByLeague&lt;/span&gt;(value) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Ember.computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;leagueData.teams.@each.league&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      const collection = Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;leagueData.teams&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; collection.filterBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;league&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, value);
    }
  });
}

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;americanLeagueTeams&lt;/span&gt;: filterByLeague(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;American&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;nationalLeagueTeams&lt;/span&gt;: filterByLeague(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;National&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});

&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That refactor removes a bit of code duplication, but we can go further.
Rather than leaning on the static dependent key of
&lt;code&gt;leagueData.teams.@each.league&lt;/code&gt;, we can make the &lt;code&gt;filterByLeague&lt;/code&gt;
function more generic if we can just pass in the key we want to filter
on:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt; &lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

 &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;filterCollectionByValue&lt;/span&gt;(collectionKey, propName, value) {
   &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Ember.computed(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{collectionKey}.&lt;span class=&quot;error&quot;&gt;@&lt;/span&gt;each.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{propName}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;, {
     get() {
       const collection = Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, collectionKey);
       &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; collection.filterBy(propName, value);
     }
   });
 }

 &lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
   &lt;span class=&quot;key&quot;&gt;americanLeagueTeams&lt;/span&gt;: filterCollectionByValue(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;leagueData.teams&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;league&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;American&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
   &lt;span class=&quot;key&quot;&gt;nationalLeagueTeams&lt;/span&gt;: filterCollectionByValue(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;leagueData.teams&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;league&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;National&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
 });
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;ES6 allows for string interpolation. This means that we can pass in the
key we want to filter by and also watch it as the dependent key. If we
need to filter a collection based off of keys other than &lt;code&gt;league&lt;/code&gt; in the
future, we
can use this generic &lt;code&gt;filterCollectionByValue()&lt;/code&gt; util rather than creating
a unique &lt;code&gt;filterByX()&lt;/code&gt; function for each key.&lt;/p&gt;

&lt;p&gt;Another dimension to the idea of dynamic dependent keys is the ability to watch an arbitrary number of them. The macro computed property &lt;code&gt;getPropertiesByKeys()&lt;/code&gt; does just that. This function allows you to provide an
arbitrary number of dependent keys and return their values:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;getPropertiesByKeys&lt;/span&gt;(...dependentKeys) {
  const computedFunc = Ember.computed({
    get() {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Ember.getProperties(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, dependentKeys);
    }
  });

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; computedFunc.property.apply(computedFunc, dependentKeys);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As you can see, this macro is more or less relying on Ember&amp;#39;s
&lt;a href=&quot;http://emberjs.com/api/classes/Ember.Object.html#method_getProperties&quot;&gt;&lt;code&gt;getProperties()&lt;/code&gt;&lt;/a&gt; method, but it allows you to specify the dependent keys at runtime.&lt;/p&gt;

&lt;p&gt;Leveraging dynamic dependent keys in computed properties opens the door
to greater refactoring. These helper functions which return a computed
property can be moved into a computed property macros util and imported
as needed throughout your project.&lt;/p&gt;

&lt;p&gt;Better yet, let my esteemed colleague, Lauren Tan, do the work for you! Her
&lt;a href=&quot;https://github.com/poteto/ember-macaroni&quot;&gt;ember-macaroni&lt;/a&gt; library wraps
up many of the macros we use at DockYard in a convenient &lt;a href=&quot;https://www.npmjs.com/package/ember-macaroni&quot;&gt;Ember
addon&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Chris McCord is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/21/chris-mccord-is-a-dockyarder" />
    <id>https://dockyard.com/blog/2015/10/21/chris-mccord-is-a-dockyarder</id>
    <category term="phoenix" label="Phoenix"/><category term="announcement" label="Announcement"/><category term="new-hire" label="New Hire"/><category term="elixir" label="Elixir"/>
    <published>2015-10-21 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/mm1doo1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;I&amp;#39;m very happy to announce that &lt;a href=&quot;http://twitter.com/chris_mccord&quot;&gt;Chris McCord&lt;/a&gt;, the creator of the 
&lt;a href=&quot;http://phoenixframework.org/&quot;&gt;Phoenix Framework&lt;/a&gt;, has joined the DockYard team!&lt;/p&gt;

&lt;p&gt;We&amp;#39;ve been working with Phoenix for nearly a year now. We love it. So
much so that we dumped Ruby on Rails and doubled down on Phoenix and
Elixir as the future. With Chris joining our team we hope to invest
heavily in that future.&lt;/p&gt;

&lt;p&gt;Chris&amp;#39; primary responsibility at DockYard is to continue building Phoenix
and make it the best choice for backend frameworks. He will be available
for consulting through DockYard in limited capacity but his knowledge is
already making its way through our team.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://dockyard.com/contact&quot;&gt;If you have a project in Phoenix we&amp;#39;d love to
chat.&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Don&#39;t Don&#39;t Override Init</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/19/2015-dont-dont-override-init" />
    <id>https://dockyard.com/blog/2015/10/19/2015-dont-dont-override-init</id>
    <category term="best-practices" label="Best Practices"/><category term="ember" label="Ember.js"/>
    <published>2015-10-19 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;The double negative in the title of this article is a jab at another
article I wrote nearly a year and a half ago: &lt;a href=&quot;https://dockyard.com/blog/2014/04/28/dont-override-init&quot;&gt;Don&amp;#39;t Override
Init&lt;/a&gt;. In that
article I advocated for never overriding the &lt;code&gt;init&lt;/code&gt; function for your
&lt;code&gt;Ember.Object&lt;/code&gt; derived classes, instead using &lt;code&gt;Ember.on&lt;/code&gt; to kick off a
function call for what you&amp;#39;d normally put into &lt;code&gt;init&lt;/code&gt;. At the time I
still believe this was a good recommendation. But times they do change,
and now that we&amp;#39;re all happily using
&lt;a href=&quot;https://babeljs.io/docs/learn-es2015/&quot;&gt;es2015&lt;/a&gt; features via
&lt;a href=&quot;http://babeljs.io&quot;&gt;Babel&lt;/a&gt; we get access to the great 
&lt;a href=&quot;https://babeljs.io/docs/learn-es2015/#default-rest-spread&quot;&gt;&lt;code&gt;spread&lt;/code&gt;&lt;/a&gt; operator.&lt;/p&gt;

&lt;p&gt;Here is how we are now writing our &lt;code&gt;init&lt;/code&gt; functions:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Object.extend({
  init() {
    &lt;span class=&quot;comment&quot;&gt;// our custom code&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is a very clean approach. More importantly: it is more
performant. Ok, but what if you were using several &lt;code&gt;Ember.on&lt;/code&gt; calls? That&amp;#39;s
easy, just break them into functions:&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;foo: on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, () =&amp;gt; {
  &lt;span class=&quot;comment&quot;&gt;// ...&lt;/span&gt;
}),

&lt;span class=&quot;key&quot;&gt;bar&lt;/span&gt;: on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, () =&amp;gt; {
  &lt;span class=&quot;comment&quot;&gt;// ...&lt;/span&gt;
}),

&lt;span class=&quot;key&quot;&gt;baz&lt;/span&gt;: on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, () =&amp;gt; {
  &lt;span class=&quot;comment&quot;&gt;// ...&lt;/span&gt;
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;init() {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.foo();
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.bar();
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.baz();
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Bonus&lt;/em&gt; points for taking back control of execution order.&lt;/p&gt;

&lt;p&gt;You don&amp;#39;t always have to &lt;code&gt;return this._super(...arguments);&lt;/code&gt; but in most
cases you should.&lt;/p&gt;

&lt;p&gt;If you are using &lt;a href=&quot;http://ember-cli.com&quot;&gt;ember-cli&lt;/a&gt; and you using
&lt;code&gt;Ember.on&lt;/code&gt; for init-like functionality you should consider this approach
instead. Do Override Init!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Actions Down, Data Up... wait what?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/14/best-practices-data-down-actions-up" />
    <id>https://dockyard.com/blog/2015/10/14/best-practices-data-down-actions-up</id>
    <category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/><category term="best-practices" label="Best Practices"/>
    <published>2015-10-14 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Marin Abernethy</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Welcome back to the fourth installment of DockYard&amp;#39;s Ember Best Practices Blog Post Series! Last time Aaron Sikes explains why we can move away from the Ember &lt;code&gt;{{input}}&lt;/code&gt; helper with angle-bracket components and improved actions. Aaron briefly discusses &amp;quot;Data down, actions up&amp;quot;, the topic of this post. So if you want a bit of context, stick around here for a minute then head over to his &lt;a href=&quot;https://dockyard.com/blog/2015/10/05/ember-best-practices-using-native-input-elements&quot;&gt;post&lt;/a&gt; afterwards.&lt;/p&gt;

&lt;h2&gt;Data Down, Actions Up&lt;/h2&gt;

&lt;p&gt;Two-way data binding is what originally attracted many to Ember.js. Data changes that affect the model are
immediately propagated to the corresponding template, and conversely, any changes made in the UI are 
promptly reflected in the underlying model. Magic! This conveniently removes unnecessary boilerplate code.&lt;/p&gt;

&lt;p&gt;However, when employed in large scale and complex applications, two-way data binding can often become more of a
headache than a blessing. Have you struggled with where to mutate your data? Have you spent an excessive amount of time tracing the source of mutated data? You are not alone. The Ember core team in their quest for continuous growth and improvement, has decided that in Ember 2.X, one-way bindings will be the default. And the ability to opt in to two-way data binding will be provided. This new adopted data flow model will simplify communication between components and can be encapsulated in the phrase: &amp;quot;data down, actions up&amp;quot;. &lt;/p&gt;

&lt;p&gt;That&amp;#39;s all well and good, but what does that actually look like in the wild? &lt;/p&gt;

&lt;h2&gt;Enough jabbering and show us!&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s build an app together. Our app will be a simple budgeting tool. Picture the money managing application,
&lt;a href=&quot;https://www.mint.com/&quot;&gt;Mint&lt;/a&gt;, and more specifically an elementary version of its &lt;a href=&quot;https://www.mint.com/how-mint-works/budgets&quot;&gt;budgeting feature&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// application/index/route.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  model () {
   &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.store.findAll(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expense&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  },

  setupController(controller, model) {
    controller.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenses&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, model);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Assume our server responds with a list of &lt;code&gt;expenses&lt;/code&gt;, where each &lt;code&gt;expense&lt;/code&gt; has a &lt;code&gt;category&lt;/code&gt; and &lt;code&gt;amount&lt;/code&gt;.
In our template we provide an input box for the user to tell us their &lt;code&gt;income&lt;/code&gt;. Then we iterate over the &lt;code&gt;expenses&lt;/code&gt;,
wrapping each &lt;code&gt;expense&lt;/code&gt; in a component. And lastly, we display their &lt;code&gt;total&lt;/code&gt; remaining money (&lt;code&gt;income - expenses&lt;/code&gt;).&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! application/index/template.hbs }}

&amp;lt;h4&amp;gt;Income:&amp;lt;/h4&amp;gt; 
{{input class=&amp;quot;income-input&amp;quot; type=&amp;quot;integer&amp;quot; value=income}}

&amp;lt;table class=&amp;quot;expenses&amp;quot;&amp;gt;
  &amp;lt;tbody&amp;gt;
    {{#each expenses as |expense|}}
      {{expense-summary expense=expense}}
    {{/each}}
  &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;

&amp;lt;h4&amp;gt;Total: {{total}}&amp;lt;/h4&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// application/index/controller.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Controller.extend({
  &lt;span class=&quot;key&quot;&gt;income&lt;/span&gt;:  &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;total&lt;/span&gt;: Ember.computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenses&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;income&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
    get() {
      const amounts = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenses&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).mapBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      const expenseTotal = amounts.reduce((previousValue, currentValue) =&amp;gt; {
        &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; previousValue + currentValue;
      }, &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;);

      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;income&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) - expenseTotal;
    }
  })
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In each row of our expenses table, we have an &lt;code&gt;expenseSummaryComponent&lt;/code&gt; that displays the expense &lt;code&gt;category&lt;/code&gt;,
provides an input box for the expense &lt;code&gt;amount&lt;/code&gt;, and has a &amp;quot;Save&amp;quot; button.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! expense-summary/template.hbs }}

&amp;lt;tr&amp;gt;
  &amp;lt;td&amp;gt;{{expense.category}}&amp;lt;/td&amp;gt;
  &amp;lt;td&amp;gt;{{input type=&amp;quot;integer&amp;quot; value=expense.amount}}&amp;lt;/td&amp;gt;
  &amp;lt;td&amp;gt;&amp;lt;button {{action &#39;amountChanged&#39;}}&amp;gt;Save&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In our &lt;code&gt;expense-summary&lt;/code&gt; component we implement the &lt;code&gt;amountChanged&lt;/code&gt; action.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// expense-summary/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    amountChanged() {
      const expense = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expense&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      expense.save();
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Yay! Done! However, we forgot something - we haven&amp;#39;t applied our new mantra, &amp;quot;data down, actions up&amp;quot;, to this code yet.The issue is that the &lt;code&gt;expenseSummaryComponent&lt;/code&gt; is updating the data (&lt;code&gt;expense.amount&lt;/code&gt;), but the data should solely belong to our &lt;code&gt;IndexController&lt;/code&gt;. Not only did the &lt;code&gt;IndexController&lt;/code&gt; give the &lt;code&gt;expenseSummaryComponent&lt;/code&gt; the &lt;code&gt;expense&lt;/code&gt; data, but it also uses the &lt;code&gt;expenses&lt;/code&gt; data to calculate the &lt;code&gt;total&lt;/code&gt;. Meaning, if the &lt;code&gt;IndexController&lt;/code&gt; was out of sync and had stale &lt;code&gt;expense&lt;/code&gt; data, it would be displaying the incorrect &lt;code&gt;total&lt;/code&gt;. While that may not be a huge concern in this simple scenario, it can be really difficult to trace in more extensive and intricate applications.&lt;/p&gt;

&lt;h3&gt;The Better Way&lt;/h3&gt;

&lt;p&gt;Instead we need to pass an action to our &lt;code&gt;expenseSummaryComponent&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! parent component: expense-table/template.hbs }}

&amp;lt;table class=&amp;quot;expenses&amp;quot;&amp;gt;
  &amp;lt;tbody&amp;gt;
    {{#each expense in expenses}}
        {{expense-summary expense=expense amountChanged=&amp;quot;update&amp;quot;}}
    {{/each}}
  &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;expenseSummaryComponent&lt;/code&gt; template looks the same as before. But this time, the action &lt;code&gt;amountChanged&lt;/code&gt;, called
when the user clicks the &amp;quot;Save&amp;quot; button in the component, will look different. &lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// expense-summary/component.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    amountChanged() {
      const expense = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expense&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.sendAction(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amountChanged&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, expense); 
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;update&lt;/code&gt; action is now sent up to the parent Component or Controller, along with the &lt;code&gt;expense&lt;/code&gt; as a parameter.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// application/index/controller.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Controller.extend({
  ...

  actions: {
    update(expense) {
      expense.save();
    }
  }
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Since &lt;code&gt;expense.save()&lt;/code&gt; is now happening in the Controller, the server will respond with the updated
version of the &lt;code&gt;expense&lt;/code&gt; (with the correct &lt;code&gt;amount&lt;/code&gt;) and update the template automatically.&lt;/p&gt;

&lt;h3&gt;The Angle-Bracket Way&lt;/h3&gt;

&lt;p&gt;In Ember, components (and solely components) are the way of the future! And the future is now, with the recent
release of &lt;a href=&quot;http://emberjs.com/blog/2015/08/16/ember-2-1-beta-released.html&quot;&gt;Ember v2.1.0&lt;/a&gt;, routable components
and &lt;a href=&quot;https://github.com/emberjs/rfcs/pull/15&quot;&gt;&lt;code&gt;angle-bracket components&lt;/code&gt;&lt;/a&gt; are live on Canary behind a feature flag.
Here is what that might look like for our budget form example.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! expense-table/template.js}}

&amp;lt;table class=&amp;quot;expenses&amp;quot;&amp;gt;
  &amp;lt;tbody&amp;gt;
    {{#each expenses as |expense|}}
      &amp;lt;expense-summary expense=expense amountChanged={{action &amp;quot;update&amp;quot;}}&amp;gt;
    {{/each}}
  &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// expense-summary/component.js&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    amountChanged() {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.attrs.amountChanged(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expense&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;));
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Final Remarks&lt;/h2&gt;

&lt;p&gt;I won&amp;#39;t dive anymore into that in this blog post. A little birdy told me that closure actions will be the subject of
a future Ember Best Practices Post. So look out for it! And remember to go back to Aaron&amp;#39;s post on &lt;a href=&quot;https://dockyard.com/blog/2015/10/05/ember-best-practices-using-native-input-elements&quot;&gt;using native input elements&lt;/a&gt; if you haven&amp;#39;t already.&lt;/p&gt;

&lt;p&gt;I have put together an &lt;a href=&quot;http://ember-twiddle.com/fc4760a5e5c475bbabc1&quot;&gt;Ember Twiddle&lt;/a&gt; with the example
we worked through today. It also demonstrates how by following the &amp;quot;data down, actions up&amp;quot; best practice,
changes in the UI of one component can easily propagate and be reflected in other components. Check it out and feel
free to play around!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Capturing the colors</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/06/capturing-the-colors" />
    <id>https://dockyard.com/blog/2015/10/06/capturing-the-colors</id>
    <category term="color" label="Color"/><category term="design" label="Design"/><category term="art" label="Art"/><category term="design-process" label="Design Process"/>
    <published>2015-10-06 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Look at fall leaves to see colors in context</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;If youâre interested in learning about color for UX Design, weâre &lt;a href=&quot;http://www.meetup.com/UX-East/events/225564114/&quot;&gt;teaching a hands-on workshop&lt;/a&gt; on October 29th!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/5G48mpK.jpg&quot; alt=&quot;Red fall foliage&quot;&gt;&lt;/p&gt;

&lt;p&gt;For me, autumn is the most fascinating time for colors. The obvious fall foliage attraction (all the streets and parks are suddenly so pretty!) and the fall fashion (summer was casual, fall calls for a slightly dressed-up, more academic, more pulled together style) combine to create an intense appetite for color. Naturally and seasonally, I am attracted to the rich earthy rust and gold in the leaves, but also the burgundy, darker navy and all kinds of leather colors that people wear to the offices downtown.&lt;/p&gt;

&lt;p&gt;There&amp;#39;s just one problem. The color effects of autumn are frustratingly difficult to capture.&lt;/p&gt;

&lt;h2&gt;Difficult to capture.&lt;/h2&gt;

&lt;p&gt;The fleeting nature of colors in the fall increases my fascination with them. Itâs not just that the leaves change every day, and shrivel up and dry within hours of bringing them home. Itâs the difficulty of reproducing how these colors feel.
Peak foliage color attracts crowds every single year. Everyone dutifully takes photos. But those photos rarely compare to the vibrant feeling in real life.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/dbESday.jpg&quot; alt=&quot;Comparing fall colors to an approximation of what the camera might see&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How the colors feel in real life (left) does not always match up to the photographic results (right). But which one is more ârealâ?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;You canât always capture whatâs in your head&lt;/h2&gt;

&lt;p&gt;The reason photos often donât live up to out vibrant expectations (think ~90% of all sunset photos ever) is partially that the camera is only able to capture a small part of what our eye can see (the human eye has a very high dynamic range), and partially our brain.&lt;/p&gt;

&lt;p&gt;The way our brains âreadâ colors is not only based on the colorsâ measurable intensity, hue, and brightness, but also on the context. For fall foliage specifically, we might âreadâ a very saturated orange in the maple leaves when they are surrounded by less saturated brown leaves, grass or buildings, and against a complimentary blue sky.&lt;/p&gt;

&lt;p&gt;So, I imagine that reality is somewhere in-between: my brain makes the fall colors feel very intense, while a camera might dull them in the process of trying to capture all the information.&lt;/p&gt;

&lt;h2&gt;A way to look at colors&lt;/h2&gt;

&lt;p&gt;Today at the library, I picked up this book on colors â &lt;em&gt;Mix your own watercolors : an artistâs guide to successful color mixing&lt;/em&gt; by John Lidzey. I have painted with watercolors for a while, but this specific book attracted me because of its focus on mixing specific shades of colors and getting predictable results. In the introduction, John Lidzey makes an important point distinction: colors will always appear to be a certain way, but we actually need to measure and isolate them to accurately understand the hue and value of the color before we can reproduce it. Context can change a color, and we can only truly see it by isolating a swatch.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/0s063iG.jpg&quot; alt=&quot;Open book with swatches&quot;&gt;&lt;/p&gt;

&lt;p&gt;He suggests making a simple tool to help judge colors: a white paper card with a small square cut out of it. Because I am interested in color for many uses, not just on (white) watercolor paper, I modified this tool to have a neutral gray and a black context for the small cut-out as well.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/b8GGdww.jpg&quot; alt=&quot;DIY - making a color tool&quot;&gt;&lt;/p&gt;

&lt;p&gt;DIY color evaluation tool!&lt;/p&gt;

&lt;h2&gt;Hereâs what I found&lt;/h2&gt;

&lt;p&gt;I used my new, very scientific (also, a bit like magic!) color analyzing tool. I found actual autumn leaf colors to be more complex and less vibrant than they first appear. I also confirmed that context can significantly alter the perception of a colorâââa &lt;a href=&quot;https://yalepress.yale.edu/book.asp?isbn=9780300115956&quot;&gt;concept&lt;/a&gt; I had learned in my freshman year of design school, but keep having to go back to look deeper.&lt;/p&gt;

&lt;p&gt;Hereâs an exercise straight from the book:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/NhTUABs.jpg&quot; alt=&quot;book without gray swatch&quot;&gt;&lt;/p&gt;

&lt;p&gt;The colors in the still life appear more vibrant than the paint swatches next to them.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/8R60zRH.jpg&quot; alt=&quot;book with gray swatch&quot;&gt;&lt;/p&gt;

&lt;p&gt;However, by comparing the swatch of mixed paint to an isolated swatch of the still life, we see the match is very close. Context makes such a difference!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/oxeq4tw.jpg&quot; alt=&quot;brown oak leaf on felt&quot;&gt;&lt;/p&gt;

&lt;p&gt;The golden-brown leaf suddenly feels dull when brought in to photograph on a lighter color. But the actual color swatch, when framed by gray, is quite saturated and warm. A good choice of context to bring out this kind of brown is any neutral, like I show here with felt.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/qNmw2K3.png&quot; alt=&quot;yellow leaf in three views&quot;&gt;&lt;/p&gt;

&lt;p&gt;Here, a yellow leaf looks quite a bit more intense either framed by gray, or on a backing of a less saturated color.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/d1jUz3R.jpg&quot; alt=&quot;yellow leaf on top of red leaves&quot;&gt;&lt;/p&gt;

&lt;p&gt;In a pile of leaves, this yellow looks saturated.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/iLk9Xzf.jpg&quot; alt=&quot;yellow leaf on white&quot;&gt;&lt;/p&gt;

&lt;p&gt;The yellow by itself, on a lighter background, still looks quite vibrant.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/8mKTVwS.jpg&quot; alt=&quot;yellow leaf + flower&quot;&gt;&lt;/p&gt;

&lt;p&gt;Compared with a very saturated yellow flower, we see that the leaf was not such a saturated color after all.&lt;/p&gt;

&lt;h2&gt;What to do&lt;/h2&gt;

&lt;p&gt;In summary â I highly recommend making this simple color context tool. It can help evaluate and compare colors in nature, and understand them better. Also, when expectations do not line up with reality, it could be that because the subject was removed from the environment in which it was first evaluated.
When I design, I need to use color well. Todayâs exercise helped me get a better understanding of just how important context is. I might alter my process in the future, to start with establishing a âbackdropâ, or a context, for my color selections. Just like a painter, I might âunderpaintâ my Photoshop file before I start fine-tuning the accent colors for any given layout.&lt;/p&gt;

&lt;p&gt;And I might just use the little gray square trick on my computer screen, when no one is looking.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Using Native Select Elements</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/05/ember-best-practices-using-native-input-elements" />
    <id>https://dockyard.com/blog/2015/10/05/ember-best-practices-using-native-input-elements</id>
    <category term="ember" label="Ember.js"/><category term="best-practices" label="Best Practices"/>
    <published>2015-10-05 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Aaron Sikes</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;This is the third in a &lt;a href=&quot;/blog/categories/ember&quot;&gt;series of posts&lt;/a&gt; designed
to share our experiences around developing Ember.js apps and the best
practices that we&amp;#39;ve found while doing so. Check out Lin&amp;#39;s post on
&lt;a href=&quot;/blog/2015/09/25/ember-best-practices-acceptance-tests&quot;&gt;page objects and acceptance tests&lt;/a&gt;, or Estelle&amp;#39;s post on
&lt;a href=&quot;/blog/2015/09/18/ember-best-practices-avoid-leaking-state-into-factories&quot;&gt;not leaking state into factories&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Closure actions&lt;/h2&gt;

&lt;p&gt;Ember 1.13 came with the release of &lt;a href=&quot;https://github.com/emberjs/rfcs/blob/master/text/0050-improved-actions.md&quot;&gt;improved actions&lt;/a&gt;.
A side effect of this feature is that it enables us to move away from
&lt;code&gt;{{view &amp;#39;select&amp;#39;}}&lt;/code&gt; and simply use DOM &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; elements with actions.&lt;/p&gt;

&lt;p&gt;&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;trouble with forms/form elements in ember?&amp;#10;&amp;#10;Turn out in 1.13.3 you can just use &amp;quot;THE DOM&amp;quot;&amp;#10;&amp;#10;&lt;a href=&quot;http://t.co/9U73q0KOOE&quot;&gt;http://t.co/9U73q0KOOE&lt;/a&gt;&lt;/p&gt;&amp;mdash; Stefan Penner (@stefanpenner) &lt;a href=&quot;https://twitter.com/stefanpenner/status/618530886162579456&quot;&gt;July 7, 2015&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;His linked JSBin links to Ember canary and no longer works, but a clone
modified to use 1.13 is available &lt;a href=&quot;http://emberjs.jsbin.com/futokumufe/edit?html,js,output&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You are probably familiar with the previous action bubbling semantics.
Actions in a component are isolated within that component. Actions
outside a component bubble first through the current controller, then
through the route hierarchy.&lt;/p&gt;

&lt;p&gt;The new approach of closure actions is simply to wrap this action up in
a function and pass it around. Anyone can call this function later. And
since the context is wrapped up in the function closure, the caller does
not need to know where it came from.&lt;/p&gt;

&lt;p&gt;For us, the important thing is that it enables us to bind actions
directly to elements, like this: &lt;code&gt;&amp;lt;select onchange={{action &amp;quot;doThing&amp;quot;}}&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;What&amp;#39;s wrong with &lt;code&gt;{{view &amp;#39;select&amp;#39;}}&lt;/code&gt;?&lt;/h2&gt;

&lt;p&gt;Ember is moving away from two of the core concepts used by &lt;code&gt;{{view
&amp;#39;select&amp;#39;}}&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Views&lt;/h3&gt;

&lt;p&gt;The Ember team, as well as many people in the community building
Ember apps have discovered that the confusion around view scopes
has been a huge source of hassle and bugs. The explicit scoping of
components is much more maintainable. Thus, the Views section has been
removed from the Ember guides, and the &lt;code&gt;{{view}}&lt;/code&gt; helper has been
&lt;a href=&quot;http://emberjs.com/api/classes/Ember.Templates.helpers.html#method_view&quot;&gt;deprecated&lt;/a&gt;. Nowadays, you get one view to go with
your route, and otherwise &lt;code&gt;View&lt;/code&gt; serves simply as a superclass to
&lt;code&gt;Component&lt;/code&gt;. As we move towards routable components, even the routes&amp;#39;
views will begin to disappear.&lt;/p&gt;

&lt;h3&gt;Two-way data binding&lt;/h3&gt;

&lt;p&gt;Ember and the Ember ecosystem are also moving away from two-way bindings,
and towards a Data Down, Actions Up architecture (DDAU).&lt;/p&gt;

&lt;p&gt;Triggering an action includes context that is missing with simple data
binding. &lt;em&gt;Why&lt;/em&gt; is this value changing? Did we receive an update from
the back-end, or did the user hit save? Lacking this context can lead
to complicated conditional logic. Or, when combined with observers can
cause &lt;a href=&quot;https://youtu.be/7PUX27RKCq0?t=16m30s&quot;&gt;an infinite loop hitting your back end&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s also hard to go back once you opt-in to two-way bindings. You&amp;#39;ve
hooked up a form field with data binding, and now you realize you need
validation on that field. Oh, you also need a confirmation when it is
valid (this is some high-stakes data). You&amp;#39;ll find yourself using an
observer, or splitting your &lt;code&gt;value&lt;/code&gt; property into &lt;code&gt;previousValue&lt;/code&gt; and
&lt;code&gt;currentValue&lt;/code&gt; properties. It is easier to hook in for these kinds of
things when triggering actions instead.&lt;/p&gt;

&lt;p&gt;There&amp;#39;s also an issue of trust and boundaries. It turns out, &lt;a href=&quot;https://github.com/emberjs/rfcs/blob/master/text/0015-the-road-to-ember-2-0.md#one-way-bindings-by-default&quot;&gt;&amp;quot;components
want to be able to hand out data to their children without having to be
on guard for wayward mutations.&amp;quot;&lt;/a&gt; Data flowing only
in one direction keeps things more predictable.&lt;/p&gt;

&lt;h2&gt;Okigetit, how do I do it?&lt;/h2&gt;

&lt;p&gt;Well, &lt;a href=&quot;http://emberjs.jsbin.com/futokumufe/edit?html,js,output&quot;&gt;Stefan&amp;#39;s JSBin&lt;/a&gt; I spoke about above is really a better
example than I could give here. But, basically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a DOM &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; tag, and use an &lt;code&gt;{{#each}}&lt;/code&gt; to render option tags.&lt;/li&gt;
&lt;li&gt;Bind an action to its &lt;code&gt;onchange&lt;/code&gt; attribute.&lt;/li&gt;
&lt;li&gt;Create an action handler to set the property value.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;But what about &lt;code&gt;{{input}}&lt;/code&gt;?&lt;/h2&gt;

&lt;p&gt;Although &lt;code&gt;{{input}}&lt;/code&gt; behaves more like a component than a view, there
are similar issues around the data binding.&lt;/p&gt;

&lt;p&gt;However, it turns out the same approach as above does not work quite as well with
&lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; tags. Because of how HTMLBars re-renders views, any time you
type a character, your cursor will be reset to the end of the text
field. This is awful! There&amp;#39;s a way around it, using the side effects of
&lt;a href=&quot;http://emberjs.com/api/classes/Ember.View.html#method_readDOMAttr&quot;&gt;readDOMAttr()&lt;/a&gt;. I won&amp;#39;t go into it here, but Rob Jackson
has put together a small &lt;a href=&quot;http://ember-twiddle.com/2d7246875098d0dbb4a4&quot;&gt;example component&lt;/a&gt; using this technique.&lt;/p&gt;

&lt;p&gt;May your forms be filled, your inputs valid, and your error template
never render!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This post has been edited. It originally recommended using
&lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; tags with actions. Because of the issues mentioned around
cursor position, it has been changed to discuss &lt;code&gt;select&lt;/code&gt; instead.&lt;/em&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Announcing the Design Sprints Guide</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/10/05/announcing-design-sprint-guide" />
    <id>https://dockyard.com/blog/2015/10/05/announcing-design-sprint-guide</id>
    <category term="user-experience" label="User Experience"/><category term="design-process" label="Design Process"/><category term="design" label="Design"/>
    <published>2015-10-05 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>Collaborative documentation for the road ahead</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/wgebVlz.png&quot; alt=&quot;Design Sprints&quot;&gt;&lt;/p&gt;

&lt;p&gt;Weâre extremely excited to announce the release of our first version of the &lt;a href=&quot;https://dockyard.com/design-sprints&quot;&gt;Design Sprints Guide&lt;/a&gt;. This releases focuses on a special 4-day variant of the ever popular rapid-validation product design methodology.&lt;/p&gt;

&lt;p&gt;In this guidebook we provide everything you can (and cannot) expect of the methodology, the processes and tools you can use for running a design sprint yourself, and a boat-load of resources for further reading.&lt;/p&gt;

&lt;p&gt;This content is free and weâd love for those already running sprints to contribute wisdom from their experiences. For now, anyone whoâd like to make edits, suggestions, or additions to this guide may send pull requests or open issues on the github repository. The README has some instructions for how weâll manage these.&lt;/p&gt;

&lt;p&gt;Plans for future releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding the original 5-day process plan.&lt;/li&gt;
&lt;li&gt;Adding more real life examples / photographed documentation.&lt;/li&gt;
&lt;li&gt;Creating tools that allow readers to suggest and accept additions or edits on the guide.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We hope youâll find this guide useful. If not, we really hope youâll help us improve it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Huge credit and thanks to the DockYard design team for putting the Design Sprints Guide together:&lt;/strong&gt; Maria Matveeva (&lt;a href=&quot;https://twitter.com/rgbcolor&quot;&gt;@rgbcolor&lt;/a&gt;), Ashley Treni (&lt;a href=&quot;https://twitter.com/ashleytreni&quot;&gt;@ashleytreni&lt;/a&gt;), Cory Tanner (&lt;a href=&quot;https://twitter.com/ctannerweb&quot;&gt;@ctannerweb&lt;/a&gt;), Amanda Chueng (&lt;a href=&quot;https://twitter.com/acacheung&quot;&gt;@acacheung&lt;/a&gt;), Tim Walsh (&lt;a href=&quot;https://twitter.com/imakemusic&quot;&gt;@imakemusic&lt;/a&gt;), and Patrick Branigan (&lt;a href=&quot;https://twitter.com/pbranigan&quot;&gt;@pbranigan&lt;/a&gt;).&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: DRYer and less fragile Acceptance Tests</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/09/25/ember-best-practices-acceptance-tests" />
    <id>https://dockyard.com/blog/2015/09/25/ember-best-practices-acceptance-tests</id>
    <category term="best-practices" label="Best Practices"/><category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/>
    <published>2015-09-25 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Lin Reid</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;This is the second in a series of posts designed to share our experiences around developing Ember.js apps and the best practices that we&amp;#39;ve found while doing so.
If you missed the first post from Estelle about &lt;a href=&quot;https://dockyard.com/blog/2015/09/18/ember-best-practices-avoid-leaking-state-into-factories&quot;&gt;not leaking state into factories&lt;/a&gt; you should check it out!&lt;/p&gt;

&lt;h3&gt;Intro&lt;/h3&gt;

&lt;p&gt;In this post, I&amp;#39;m going to be talking about writing less fragile acceptance tests that are easier to maintain.
Renaming CSS classes or refactoring the HTML structure of an application can cause our acceptance tests to fail, even if the end-user experience is the same.
When this happens, it&amp;#39;s not uncommon to spend a disproportionate amount of time fixing broken tests rather than refactoring code.
If that sounds familiar, I&amp;#39;ve got a few approaches that you can use to create less fragile acceptance tests.
And more than that, when they do break, you can fix your test logic in one place rather than in every test that&amp;#39;s failing.&lt;/p&gt;

&lt;h2&gt;Minimize coupling tests to presentation&lt;/h2&gt;

&lt;p&gt;The first approach weâre going to talk about is decoupling your acceptance tests from the HTML structure and CSS of your application.
If your tests are breaking due to semantic HTML or class name changes but the end experience to the user is nearly exactly the same, this should be a red flag that your tests are too closely coupled to the HTML and CSS of your application.
Our acceptance tests should be from the perspective of a user interacting with the application.
A user doesnât care about whether the element they are clicking on is a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; or a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; or whether we use a class name of &lt;code&gt;post&lt;/code&gt; or &lt;code&gt;blog-post&lt;/code&gt;.
They care that they can read a blog post, comment on it, and like it.&lt;/p&gt;

&lt;p&gt;However, we canât perfectly decouple our tests from presentation, as we still need to be able to find the elements that we need to interact with and make assertions against.
One approach to minimizing the coupling is to add a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes&quot;&gt;data attribute&lt;/a&gt; to elements that we want to target during our tests.
Data attributes are attributes that are prefixed with &lt;code&gt;data-&lt;/code&gt; and are intended to store meta data on elements:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;div data-foo=&amp;quot;some arbitrary data&amp;quot; data-bar=&amp;quot;123&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Example test using data attributes&lt;/h3&gt;

&lt;p&gt;We can use these data attributes to identify elements that will be interacted with in our tests:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;div class=&amp;quot;post-likes&amp;quot;&amp;gt;
  &amp;lt;span class=&amp;quot;likes-count&amp;quot; data-test-selector=&amp;quot;post-likes-count&amp;quot;&amp;gt;{{likesCount}}&amp;lt;/span&amp;gt;
  &amp;lt;button class=&amp;quot;btn like&amp;quot; {{action &amp;quot;likePost&amp;quot;}} data-test-selector=&amp;quot;post-like-button&amp;quot;&amp;gt;Like&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a user can like a post&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  assert.expect(&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;);

  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;posts/1&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  andThen(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    const likesCount = find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[data-test-selector=&amp;quot;post-likes-count&amp;quot;]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    assert.equal(likesCount.text(), &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;precondition - likes count starts at 0&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  });

  click(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[data-test-selector=&amp;quot;post-like-button&amp;quot;]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  andThen(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    const likesCount = find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[data-test-selector=&amp;quot;post-likes-count&amp;quot;]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    assert.equal(likesCount.text(), &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;clicking the like post button increments the likes count&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, if we want to refactor our like button so it contains the likes count and change around some class names...&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;button class=&amp;quot;btn like-post&amp;quot; {{action &amp;quot;likePost&amp;quot;}} data-test-selector=&amp;quot;post-like-button&amp;quot;&amp;gt;
  &amp;lt;span class=&amp;quot;count&amp;quot; data-test-selector=&amp;quot;post-likes-count&amp;quot;&amp;gt;{{likesCount}}&amp;lt;/span&amp;gt; Likes
&amp;lt;/button&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Our test still passes without having to update our test logic because we&amp;#39;re not targeting elements based on their class names or their relation to other elements on the page.
Success!&lt;/p&gt;

&lt;h2&gt;Page Object Pattern&lt;/h2&gt;

&lt;p&gt;The next approach we&amp;#39;re going to talk about is using the Page Object pattern to DRY out our test logic.
The goal of a Page Object is to represent an area of your UI that gets interacted with during tests.
Page Objects are responsible for abstracting away the details of how to target and interact with elements in the DOM and providing an API that can be used in tests for page interactions.
The name Page Object can be a bit misleading.
Most &amp;quot;pages&amp;quot; have a bit too much going on for them to be encapsulated into one object.
Generally, Iâve found that it makes more sense to model Page Objects after logical chunks of the UI.
You might have a Page Object representing your nav-bar, side-bar, or a group of components that compose a logical section of the UI.
For example, you might have a Page Object that is responsible for providing an API for targeting elements of an individual post:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// tests/page-objects/post-show.js&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;// PageObject implementation using es6 Classes&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; BasePageObject from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;./base&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;; &lt;span class=&quot;comment&quot;&gt;// A base class for all page objects to extend from&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;reserved&quot;&gt;class&lt;/span&gt; PostShowPageObject &lt;span class=&quot;reserved&quot;&gt;extends&lt;/span&gt; BasePageObject {
  constructor(assert) {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.assert = assert;
  }

  &lt;span class=&quot;comment&quot;&gt;// interactions&lt;/span&gt;
  readPostId(id) {
    visit(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;posts/&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{id}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;;
  }

  clickLikeButton() {
    click(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[data-test-selector=&amp;quot;post-like-button&amp;quot;]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;;
  }

  &lt;span class=&quot;comment&quot;&gt;// assertions&lt;/span&gt;
  assertLikesCount(count, message) {
    andThen(() =&amp;gt; {
      const likesCount = find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[data-test-selector=&amp;quot;post-likes-count&amp;quot;]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      message = message || &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;likes count is: &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{count}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.assert.equal(likesCount.text(), count, message);
    });

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;;
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here&amp;#39;s what the exact same acceptance test would look like using our new Page Object:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; PostShowPageObject from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../page-objects/post-show&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;comment&quot;&gt;// other test code&lt;/span&gt;

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a user can like a post&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  assert.expect(&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; PostShowPageObject(assert)
    .readPostId(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;)
    .assertLikesCount(&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;precondition - likes count starts at 0&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    .clickLikeButton()
    .assertLikesCount(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;clicking the like post button increments the likes count&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The real benefit here is that if you need to change how you target elements, you only have to fix it in one place rather than every test that interacts with that element.
Besides the maintainability of the test logic, it makes for super clean and readable tests! One thing to note is that there is some disagreement about
whether assertions should be a part of the API of a Page Object. Some people feel that a Page Object should strictly provide an API for page interactions.
Others feel that we tend to assert around a certain set of elements in our tests and DRYing up assertion logic by including assertions in the Page Object makes sense.
In my experience, I&amp;#39;ve found that including assertion helpers in my Page Objects has saved me a ton of time when adding new tests and maintaining old tests.&lt;/p&gt;

&lt;h3&gt;Additional Resources&lt;/h3&gt;

&lt;p&gt;Mike North gave a great talk at &lt;a href=&quot;http://wickedgoodember.com/&quot;&gt;Wicked Good Ember&lt;/a&gt; last year about using Page Objects and data attributes for acceptance testing. I definitely recommend &lt;a href=&quot;http://confreaks.tv/videos/wickedgoodember2015-compose-all-the-things&quot;&gt;checking it out&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;ember-page-object&lt;/h3&gt;

&lt;p&gt;If you&amp;#39;re sold on the idea of using Page Objects and data attributes to target elements in acceptance tests,
&lt;a href=&quot;https://twitter.com/sugarpirate_&quot;&gt;Lauren&lt;/a&gt; and I created an addon called &lt;a href=&quot;https://github.com/linstula/ember-page-object&quot;&gt;ember-page-object&lt;/a&gt; that provides a base PageObject
class you can extend from to help get you started! Enjoy!&lt;/p&gt;
</content>
  </entry><entry>
    <title>What to expect from a Design Sprint</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/09/22/What-to-expect-from-a-design-sprint" />
    <id>https://dockyard.com/blog/2015/09/22/What-to-expect-from-a-design-sprint</id>
    <category term="design-sprints" label="Design Sprints"/><category term="design-strategy" label="Design Strategy"/><category term="ux-design" label="Ux Design"/>
    <published>2015-09-22 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Ashley Treni</name></author>
    <summary>Participation, outcomes, and deliverables</summary>
    <content type="html">&lt;p&gt;A design sprint is a research strategy which focuses on and explores a feature or specific part of a product. With a limited scope and a short duration of a week, a sprint can test and validate ideas about user flow, functionality, and interaction design around a specific product goal. To elaborate on &lt;a href=&quot;https://dockyard.com/blog/2015/08/17/design-sprints-what-are-they-for&quot;&gt;Maria&amp;#39;s post about Design Sprints&lt;/a&gt;, here&amp;#39;s a &amp;quot;what to expect&amp;quot; about participation, outcomes, and deliverables.&lt;/p&gt;

&lt;h2&gt;Participation&lt;/h2&gt;

&lt;p&gt;A stakeholder from the product in development is a very important participant in the design sprint, and they should expect to be hands on and present for the full sprint duration. Design sprints move very fast, and their industry knowledge and understanding of the product is key to a successful outcome. The team can move forward quickly and efficiently with the availability to ask questions and help make informed assumptions along the way. Stakeholders come with unique insights about the product that can illuminate conditions of the target market, knowledge about users, business goals, and any known limitations or pre-existing conditions up front.&lt;/p&gt;

&lt;p&gt;Planning the sprint objectives and project goals before the start of the sprint is important to stay focused on the task at hand. New ideas will arise during a sprint - the design team leader will make sure to document for later, or redirect the sprint to address those considerations if they are integral to the solution.&lt;/p&gt;

&lt;h2&gt;Outcomes&lt;/h2&gt;

&lt;p&gt;Part of establishing project goals is determining the outcomes and deliverables that result as a product of the sprint. The outcomes of a design sprint depend on the state of your product before the design sprint, and based on the project goals that were defined. The outcome of a sprint can go many different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A working prototype.&lt;/strong&gt; Usually for a one-week design sprint, the result is a clickable prototype and one or two user stories. The thinking that went into defining the user flow and key interactions can be tested and validated through the prototype and user testing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detailed wireframes and a full user flow.&lt;/strong&gt; Often times, a series of sprints are held to explore a more complex product. With each week focusing on a different facet of the product, wireframes and prototypes from each sprint can start to carry over to inform design decisions in consecutive weeks. With consecutive sprints, it is possible to explore the product more deeply and examine the connections and interdependencies between the proposed user flows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preliminary visual design.&lt;/strong&gt; If the content of a given sprint is narrow in scope, there may be time at the end of the sprint to begin visual design. Developing a visual style for the product can inform prototypes in consecutive sprints, or lay a framework for visual tone in the product itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Product direction.&lt;/strong&gt; For newer products, sprints can explore the wide landscape of possibilities to discover and prioritize the best ways to move forward. A sprint can help select and test directions early on to determine the strongest product values to put into action.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Deliverables&lt;/h2&gt;

&lt;p&gt;The deliverables for the following outcomes may come in various forms such as original files (Sketch, photoshop, illustrator documents), JPGs/PDFs/PNGs, links to online prototypes, and photographs.&lt;/p&gt;

&lt;p&gt;The outcomes of a design sprint are more strategic in nature and not a fully completed project. What youâll take away from a sprint are research tools, the skeleton of an interface with core features and interactions and, most importantly, a better understanding of the next steps for your product. Setting these expectations for participation, outcomes, and deliverables up front is imperative to a successful design sprint. &lt;/p&gt;

&lt;p&gt;We&amp;#39;re excited to share more of our process with you through our soon to be released (and free) design sprints resource guide! Signup to the DockYard newsletter below and we&amp;#39;ll let you know when it has been released.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Best Practices: Avoid leaking state into factories</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/09/18/ember-best-practices-avoid-leaking-state-into-factories" />
    <id>https://dockyard.com/blog/2015/09/18/ember-best-practices-avoid-leaking-state-into-factories</id>
    <category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/>
    <published>2015-09-18 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Estelle DeBlois</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;At DockYard, we spend a lot of time with Ember, from building web apps, creating and maintaining addons, to contributing back to the Ember ecosystem. We hope to share some of the experience we&amp;#39;ve gathered along the way through a series of blog posts that will focus on idiomatic Ember practices, patterns, anti-patterns, and common pitfalls. This is the first in that series, so let&amp;#39;s start by going back to the basics with &lt;code&gt;Ember.Object&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Ember.Object&lt;/code&gt; is one of the first things we learn as Ember developers, and to no surprise. Pretty much every object we work with in Ember, whether it&amp;#39;s a route, component, model, or service, &lt;a href=&quot;http://emberjs.jsbin.com/boqapo&quot;&gt;extends from Ember.Object&lt;/a&gt;. But every now and then, I see it used incorrectly, like this:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;items&lt;/span&gt;: [],

  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    addItem(item) {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).pushObject(item);
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To those who have encountered this before, the problem is obvious. But I&amp;#39;m sure this has trolled many developers at one time or another, so if the issue doesn&amp;#39;t immediately jump at you, keep reading!&lt;/p&gt;

&lt;h2&gt;Ember.Object&lt;/h2&gt;

&lt;p&gt;If you were to browse the &lt;a href=&quot;http://emberjs.com/api/classes/Ember.Object.html&quot;&gt;API&lt;/a&gt; and deselect all &lt;em&gt;Inherited&lt;/em&gt;, &lt;em&gt;Protected&lt;/em&gt;, and &lt;em&gt;Private&lt;/em&gt; options, you&amp;#39;ll see that &lt;code&gt;Ember.Object&lt;/code&gt; has no methods or properties of its own. The &lt;a href=&quot;https://github.com/emberjs/ember.js/blob/v2.0.2/packages/ember-runtime/lib/system/object.js&quot;&gt;source&lt;/a&gt; code couldn&amp;#39;t be any shorter. It&amp;#39;s literally just an extension of Ember&amp;#39;s &lt;code&gt;CoreObject&lt;/code&gt;, with the &lt;code&gt;Observable&lt;/code&gt; mixin applied:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; EmberObject = CoreObject.extend(Observable);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;CoreObject&lt;/code&gt; provides a clean interface for defining factories or &lt;em&gt;classes&lt;/em&gt;. It is essentially an abstraction around how you would normally create constructor functions, define methods and properties on the prototype, and then create new objects by calling &lt;code&gt;new SomeConstructor()&lt;/code&gt;. If you&amp;#39;re able to invoke methods of a superclass using &lt;code&gt;this._super()&lt;/code&gt;, or merge a set of properties into a class via &lt;a href=&quot;http://emberjs.com/api/classes/Ember.Mixin.html&quot;&gt;Mixins&lt;/a&gt;, you have &lt;code&gt;CoreObject&lt;/code&gt; to thank for. All the methods that come up often when working with Ember objects, such as &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;extend&lt;/code&gt;, or &lt;code&gt;reopen&lt;/code&gt;, are all defined there too.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Observable&lt;/code&gt; is the mixin that makes it possible to observe changes to properties on an object, and is where both &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; methods come from.&lt;/p&gt;

&lt;p&gt;When developing an Ember app, you would never use &lt;code&gt;CoreObject&lt;/code&gt; directly. You would extend from &lt;code&gt;Ember.Object&lt;/code&gt; instead. After all, Ember is all about &lt;a href=&quot;https://medium.com/the-ember-way/ember-js-reactive-programming-computed-properties-and-observers-cf80c2fbcfc&quot;&gt;reacting to changes&lt;/a&gt;, so you need the methods from &lt;code&gt;Observable&lt;/code&gt; in order to detect when a property value changes.&lt;/p&gt;

&lt;h2&gt;Defining a new class&lt;/h2&gt;

&lt;p&gt;You can define a new type of observable object by extending from &lt;code&gt;Ember.Object&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const Post = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Untitled&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;author&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Anonymous&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

  &lt;span class=&quot;key&quot;&gt;header&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    const title = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    const author = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;${title}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; by &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{author}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;New objects of type &lt;code&gt;Post&lt;/code&gt; can now be created by calling &lt;code&gt;Post.create()&lt;/code&gt;. Each post instance will inherit the properties and methods that have been defined on the &lt;code&gt;Post&lt;/code&gt; class:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const post = Post.create();
post.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Untitled&#39;&lt;/span&gt;
post.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Anonymous&#39;&lt;/span&gt;
post.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Untitled by Anonymous&#39;&lt;/span&gt;
post &lt;span class=&quot;keyword&quot;&gt;instanceof&lt;/span&gt; Post; &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; true&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can change the property values and give the post a meaningful title and author name. These values will be set on the instance, not the class, and therefore will not affect future posts that get created.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;post.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Heads? Or Tails?&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
post.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;R &amp;amp; R Lutece&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
post.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;&amp;quot;Heads? Or Tails?&amp;quot; by R &amp;amp; R Lutece&#39;&lt;/span&gt;

const anotherPost = Post.create();
anotherPost.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Untitled&#39;&lt;/span&gt;
anotherPost.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Anonymous&#39;&lt;/span&gt;
anotherPost.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Untitled by Anonymous&#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Because updating properties this way has no impact on other instances, it is easy to think that all operations done on an instance are safe. But let&amp;#39;s expand on this example a bit more.&lt;/p&gt;

&lt;h2&gt;Leaking state into the class&lt;/h2&gt;

&lt;p&gt;A post can have an optional list of tags, so we can create a property named &lt;code&gt;tags&lt;/code&gt; and default it to an empty array. New tags can be added by calling an &lt;code&gt;addTag()&lt;/code&gt; method.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const Post = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;tags&lt;/span&gt;: [],

  addTag(tag) {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).pushObject(tag);
  }
});

const post = Post.create();
post.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; []&lt;/span&gt;
post.addTag(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;constants&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
post.addTag(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
post.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [&#39;constants&#39;, &#39;variables&#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Looks like it&amp;#39;s working! But check out what happens when a second post is now created:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const anotherPost = Post.create();
anotherPost.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [&#39;constants&#39;, &#39;variables&#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Even though the goal was to create a new post with empty tags (the intended default), the post was created with the tags from the previous post. Because we never set the post&amp;#39;s &lt;code&gt;tags&lt;/code&gt; property to a new value but simply mutated the underlying array, we have effectively leaked state into the &lt;code&gt;Post&lt;/code&gt; class, which is then shared by all instances.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;post.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [&#39;constants&#39;, &#39;variables&#39;]&lt;/span&gt;
anotherPost.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [&#39;constants&#39;, &#39;variables&#39;]&lt;/span&gt;
anotherPost.addTag(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;infinity&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [&#39;constants&#39;, &#39;variables&#39;, &#39;infinity&#39;]&lt;/span&gt;
post.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [&#39;constants&#39;, &#39;variables&#39;, &#39;infinity&#39;]&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It is not the only scenario where you may confuse instance state and class state, but it is certainly one that comes up more often. In a related example, you may wish to default an object&amp;#39;s property named &lt;code&gt;createdDate&lt;/code&gt; to the current date and time by setting it to &lt;code&gt;new Date()&lt;/code&gt;. But &lt;code&gt;new Date()&lt;/code&gt; will only get evaluated once, when the class is defined. So no matter when you create new instances of that class, they will all share the same &lt;code&gt;createdDate&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const Post = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;createdDate&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Date()
});

const postA = Post.create();
postA.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;createdDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; Fri Sep 18 2015 13:47:02 GMT-0400 (EDT)&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;// Sometime in the future...&lt;/span&gt;
const postB = Post.create();
postB.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;createdDate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; Fri Sep 18 2015 13:47:02 GMT-0400 (EDT)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Keeping things under control&lt;/h2&gt;

&lt;p&gt;In order to avoid sharing tags between posts, the &lt;code&gt;tags&lt;/code&gt; property would need to be set when the object is initialized:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const Post = Ember.Object.extend({
  init() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.tags = [];
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Since &lt;code&gt;init&lt;/code&gt; is called whenever you call &lt;code&gt;Post.create()&lt;/code&gt;, each post instance will always get its own &lt;code&gt;tags&lt;/code&gt; array. Alternatively, you could make &lt;code&gt;tags&lt;/code&gt; a computed property. It won&amp;#39;t observe anything, but will be unique to each instance:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const Post = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;tags&lt;/span&gt;: computed({
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; [];
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;It should be obvious now why you should not write components like the example I showed at the beginning of this post. Even if the component only appears once on a page, when you leave the route, only the component instance gets destroyed, not the factory. So when you come back, a new instance of the Component will get created, and this new component will have traces of the previous time you visited the page.&lt;/p&gt;

&lt;p&gt;This error may be encountered when using mixins as well. Even though &lt;code&gt;Ember.Mixin&lt;/code&gt; is not an &lt;code&gt;Ember.Object&lt;/code&gt;, properties and methods defined on the mixin get merged with the &lt;code&gt;Ember.Object&lt;/code&gt; you mix it into. The result would be the same: you may end up sharing state between all objects that use the mixin.&lt;/p&gt;

&lt;p&gt;If you found this post helpful, stay tuned for more blog posts from myself and fellow DockYarders on Ember best practices in the future!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Design is about systems</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/09/10/design-is-about-systems" />
    <id>https://dockyard.com/blog/2015/09/10/design-is-about-systems</id>
    <category term="design-thinking" label="Design Thinking"/><category term="observations" label="Observations"/><category term="ux-design" label="Ux Design"/><category term="design" label="Design"/>
    <published>2015-09-10 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>A design change is not just a design change</summary>
    <content type="html">&lt;p&gt;As I commute, every time I have to pick between risk and delay.&lt;/p&gt;

&lt;p&gt;There is an intersection that takes a pedestrian three separate lights to cross. For cars, itâs just one. &lt;em&gt;If you obey all traffic signals&lt;/em&gt; youâll cross this intersection in two traffic-light cycles heading downtown. In the opposite direction, it can take three full cycles.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Uvxx0zl.png&quot; alt=&quot;Three crosswalks to get across one busy street from point A to point B&quot;&gt;&lt;/p&gt;

&lt;p&gt;Clearly, this leads to frustration for pedestrians. With cars potentially coming from three different directions (look at Crossing 2), itâs easy to look to just one side, assume there is no traffic, and jaywalk. It often happens just as the cars start moving. In addition to being dangerous for people, this slows down the cars and buses even more, adding to residual delays as they eventually clear the intersection on red.&lt;/p&gt;

&lt;h2&gt;This intersection design is stupid&lt;/h2&gt;

&lt;p&gt;As a pedestrian, I have a choice between jaywalking (running) as I glance left, right, and back to see if any cars are coming - or waiting several minutes extra to cross. It seems such an injustice that I have to request a pedestrian light up to three times while cars clear this monstrous intersection in just one. As a user of this intersection, I feel like I am an afterthought, not a primary consideration. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What if we mandate that all intersections be crossable in one light? What if we prioritize pedestrians, not cars?&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;I start to imagine potential legislation, participating in a &amp;quot;healthy city&amp;quot; campaign of some sort, and even a crosswalk design that would accommodate a faster, safer crossing for me.&lt;/p&gt;

&lt;h2&gt;This intersection is part of a system&lt;/h2&gt;

&lt;p&gt;Then I think about it more. Why was this intersection designed to accommodate cars better than pedestrians? Why do most cities in the US still feel like theyâre planned for cars and not people? Because they are. Long story. I start to imagine all the infrastructure changes that might be required for this seemingly simple change: to alter the path of a crosswalk, and make it feel more efficient.&lt;/p&gt;

&lt;p&gt;I think this way because as a designer, I am responsible for making sure that the things I build and âmake prettyâ actually work - and for more than one type of user. I donât put a button or a variable into a mockup unless I know it can be supported by engineering, and is necessary for the user. Because of this sense of responsibility, I canât really enjoy lofty, speculative discussions about potential changes it might be nice to make. &lt;/p&gt;

&lt;h2&gt;Design thinking is both a blessing and a curse&lt;/h2&gt;

&lt;p&gt;As a designer, I canât help but think about how the environment around me works, and why. Iâm a walking critique machine, a small nudge will get it started. I can see, or at least imagine, the systems that stand behind every designed detail of my life.&lt;/p&gt;

&lt;p&gt;But even when I can often see clear ways to fix situations that annoy me, I can just as clearly see why change wonât usually be easy or fast. A change in my path across a traffic intersection is not just about the intersection. It involves the systems that control traffic flow on the three streets. One of these streets goes underground to flow into a highway, and another exits to Bostonâs busy Financial District.&lt;/p&gt;

&lt;p&gt;A design approach is powerful precisely because we take into account the systems, requirements, and groups of users who will interact with the thing we design. We aim to help people accomplish their goals while minimizing potential frustrations. This is a lot of responsibility, but itâs exactly what makes our work powerful.&lt;/p&gt;

&lt;p&gt;And while we can never know about all the components of the systems we design for from the start, we must ask questions and rely on othersâ expertise to draw conclusions. The ultimate responsibility in design is to think holistically.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Define: Functional Decoration</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/09/04/define-functional-decoration" />
    <id>https://dockyard.com/blog/2015/09/04/define-functional-decoration</id>
    <category term="design" label="Design"/><category term="design-process" label="Design Process"/><category term="user-experience" label="User Experience"/>
    <published>2015-09-04 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>Due diligence to repair a meaningful technique</summary>
    <content type="html">&lt;p&gt;If youâre unfamiliar with the implications of decoration in design, a good place to start is to read Beatrice Wardeâs &lt;a href=&quot;http://gmunch.home.pipeline.com/typo-L/misc/ward.htm&quot;&gt;âThe Crystal Goblet, or Printing Should Be Invisibleâ&lt;/a&gt;. It sums up fairly well a belief I carry to the products we produce at DockYard.&lt;/p&gt;

&lt;p&gt;Designers working in graphic, industrial, architectural, and user experience design have experienced many revolutions of overly decorative design followed by a great decorative purge. A most recent example of this is the explosion of âflat designâ and aggression turned toward all things skeuomorphic. This was inevitable, and I welcome the sea change.&lt;/p&gt;

&lt;p&gt;However, I think if weâre able to open our hearts for a minute to unpopular ideas, weâll find that decoration does indeed have a functional role in design. I think that role could be called Functional Decoration. Let me explain what I think Functional Decoration is by explaining what I think it can do.&lt;/p&gt;

&lt;p&gt;Functional Decoration is decoration that assists in creating a new context through which expectations shift, or distort our sense of &amp;quot;normal&amp;quot;, to allow us to amplify the messages within the content it surrounds. It can let usÂ exemplify the experience of a thing better than purely representing it in the written word. It can be effective in emphasizing the tone of a process, providing a sense of the experience of an event, or perhaps even an expectation of the performance of a product.&lt;/p&gt;

&lt;p&gt;Can you tell me if you felt real emotions when seeing Inside Out, Up, Spirited Away, or Princess Mononoke? What if we stripped the âdecorativeâ medium from these films? The answer is we would have a very different experience with the content. I think proponents for moderate use of decoration are experiencing something similar to attempting to get someone who refuses to watch anime to watch a single animated film. It&amp;#39;s an uphill battle, but I digress.&lt;/p&gt;

&lt;p&gt;I believe useful decoration - Functional Decoration - extends the readers&amp;#39; imagination to help their mind do the dirty work of turning text into imagined experiences or expectations. Done well, it can be much better than the content on its own.&lt;/p&gt;

&lt;p&gt;Here are a few examples of what I&amp;#39;d call Functional Decoration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://2015.xoxofest.com/&quot;&gt;XOXOs changing background pattern and use of overlay yellow on blue.&lt;/a&gt; The absence of photography, the unabashed use of a basic but vibrant blue and yellow, and the dynamic overlaying shapes describe an inclusive nature of their event well: âyou&amp;#39;re with friends, it&amp;#39;s ok to be you hereâ&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://superlooper.universlabs.co.uk/&quot;&gt;Super-Loopers &amp;quot;pixelated&amp;quot; visuals&lt;/a&gt; pay homage to the environment that inspired the software but also act as a visual description of the sound you&amp;#39;re hearing.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.bloomberg.com/graphics/2015-paul-ford-what-is-code/&quot;&gt;Bloombergâs &amp;quot;What is Code?&amp;quot;&lt;/a&gt; by Paul Ford uses graphics and pattern as Functional Decoration in that they themselves are illustrations of the content. They facilitate a sometimes humorous and other times very awe-struck wonder of the origins of computing and its concentric cultures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end of the day, my goal with the concept of Functional Decoration is to do necessary repair from damages caused by scorched earth dismantling of decoration (such as skueomorphism) and to help myself and my team to make better use of the communicative tool decoration can be.&lt;/p&gt;

&lt;p&gt;And I really just wish there was a better word than &amp;quot;decoration&amp;quot;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Clear communication through HTML and GitHub</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/09/02/clear-communication-through-html" />
    <id>https://dockyard.com/blog/2015/09/02/clear-communication-through-html</id>
    <category term="html" label="Html"/>
    <published>2015-09-02 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Cory Tanner</name></author>
    <summary>A technique for clear communication between web application teams through HTML and GitHub</summary>
    <content type="html">&lt;p&gt;If you follow the DockYard blog I am sure you are familiar with how we structure our teams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can get a feel for how our designers operate by taking a look at Steve&amp;#39;s post, &lt;a href=&quot;https://dockyard.com/blog/2015/01/14/sr-ui-designer&quot;&gt;Job: Senior UI &amp;amp; Visual Designer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UX Dev (User Experience Development)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Brian has a great post describing the UX Dev team, &lt;a href=&quot;https://dockyard.com/blog/2014/08/06/the-most-difficult-position-to-hire-for-in-tech-right-now&quot;&gt;The most difficult position to hire for in tech right now&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mainly with &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember.js&lt;/a&gt; the Development team wires up all of the functionality required with the HTML and CSS provided by UX Dev.&lt;/p&gt;

&lt;h2&gt;Our current process&lt;/h2&gt;

&lt;p&gt;What helps us the most when we have multiple teams on a project is clear communication.&lt;/p&gt;

&lt;p&gt;DockYard has methods of communication between all three teams but this blog post will be focusing on methods the UX Dev team uses to communicate with the Development team.&lt;/p&gt;

&lt;p&gt;Our UX Dev team is always looking to make work easier for the Development team and a simple way to do that is through how we communicate an application&amp;#39;s conditionals. When we receive designs of the application we need to communicate to Development what the conditionals are in a clear and organized way.&lt;/p&gt;

&lt;p&gt;We have done this through our HTML templating comments and this alone has worked well.&lt;/p&gt;

&lt;p&gt;In a previous post we went over how to add comments to your code in &lt;a href=&quot;https://dockyard.com/blog/2015/03/31/helping-our-engineers&quot;&gt;Helping Our Engineers&lt;/a&gt;, and we go over two methods of communication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; we use &lt;a href=&quot;http://handlebarsjs.com/&quot;&gt;Handlebars&lt;/a&gt; for our templating.&lt;/p&gt;

&lt;h3&gt;Pseudo-code comments&lt;/h3&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;a class=&amp;quot;t-link&amp;quot; href=&amp;quot;&amp;quot;&amp;gt;about&amp;lt;/a&amp;gt;
&amp;lt;a class=&amp;quot;t-link&amp;quot; href=&amp;quot;&amp;quot;&amp;gt;contact&amp;lt;/a&amp;gt;
{{! if signed in}}
  &amp;lt;a class=&amp;quot;t-link&amp;quot; href=&amp;quot;&amp;quot;&amp;gt;manage&amp;lt;/a&amp;gt;
{{! else}}
  &amp;lt;a class=&amp;quot;t-link&amp;quot; href=&amp;quot;&amp;quot;&amp;gt;sign in&amp;lt;/a&amp;gt;
{{! end if}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This lets our developers know that &lt;code&gt;if&lt;/code&gt; the user signs into the application, the manage link is added to the HTML, &lt;code&gt;else&lt;/code&gt; the sign in link should be present.&lt;/p&gt;

&lt;p&gt;This method works great for adding notifications to the page, you just need to say the following.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;input class=&amp;quot;button&amp;quot;&amp;gt;Log In&amp;lt;/input&amp;gt;
{{! if &amp;lt;input&amp;gt; has errors on submit}}
  &amp;lt;div class=ânotificationâ&amp;gt;
    ...
  &amp;lt;/div&amp;gt;
{{! end if}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;TODO comment&lt;/h3&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! TODO: Toggle class .is-selected on &amp;lt;a&amp;gt; when active}}
&amp;lt;a class=&amp;quot;t-link&amp;quot; href=&amp;quot;&amp;quot;&amp;gt;about&amp;lt;/a&amp;gt;
&amp;lt;a class=&amp;quot;t-link&amp;quot; href=&amp;quot;&amp;quot;&amp;gt;contact&amp;lt;/a&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If we donât need to add complete blocks of code to the HTML we will use a TODO comment to let the developers know a class needs to be added to the next line of code.&lt;/p&gt;

&lt;h2&gt;Whatâs new: Track Everything&lt;/h2&gt;

&lt;p&gt;In addition to adding comments it is recommended to provide a trackable issue referencing the comment in your code. On GitHub this is very easy and we can assign the issue to a team member.&lt;/p&gt;

&lt;p&gt;We donât do this for every individual comment but rather make a checklist in the GitHub issue per modular &lt;a href=&quot;http://emberjs.com/api/classes/Ember.Component.html&quot;&gt;component&lt;/a&gt; or one issue for simple pages.&lt;/p&gt;

&lt;p&gt;An example of a simple page would be a static &amp;quot;About Us&amp;quot; page that only has about 1 - 2 comments and no complex conditionals.&lt;/p&gt;

&lt;h3&gt;Issue example&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/8VHiilm.png&quot; alt=&quot;GitHub issue for component comments&quot;&gt;&lt;/p&gt;

&lt;p&gt;Having trackable issues for comments is helpful because there can be so many of them. Keeping everything organized in a project management system like GitHub is very helpful.&lt;/p&gt;

&lt;h3&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;Our goal as UX Developers is to provide crystal clear communication with the Design and Development teams so the client gets the best product possible.&lt;/p&gt;

&lt;p&gt;Having standardized techniques for communicating the application HTML conditionals within your team can greatly help the workflow and make everyone&amp;#39;s life easier.&lt;/p&gt;

&lt;p&gt;I hope this helps your templating process with HTML and provides clear communication with your team!&lt;/p&gt;
</content>
  </entry><entry>
    <title>CSS Tooltips: What clip-path &amp; gradients can do for us</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/08/27/css-tooltips" />
    <id>https://dockyard.com/blog/2015/08/27/css-tooltips</id>
    <category term="css" label="Css"/>
    <published>2015-08-27 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Amanda Cheung</name></author>
    <summary>A way to use clip-path and linear gradients to further customize tooltips.</summary>
    <content type="html">&lt;h2&gt;What I wanted&lt;/h2&gt;

&lt;p&gt;This came about when I was trying to create an error tooltip with borders and a transparent background following this design:
&lt;img src=&quot;https://i.imgur.com/baJdTwK.png&quot; alt=&quot;Design for customized tooltip&quot;&gt;&lt;/p&gt;

&lt;p&gt;It has a subtle wave texture to it so it was important that the
tooltip held transparency. I also wanted to set up a constraint for myself
to not add extra HTML elements.&lt;/p&gt;

&lt;h2&gt;The old solutions and why they didnât work&lt;/h2&gt;

&lt;p&gt;Previously, when I wanted to implement a tooltip, I could make it
transparent without a border OR have a border and the background would
have to be opaque. The only way I knew to do borders was stacking the before and after pseudo elements to &lt;i&gt;simulate&lt;/i&gt; a border &lt;a href=&quot;http://davidwalsh.name/css-tooltips&quot;&gt;like so&lt;/a&gt;. This method prevented transparent backgrounds because one pseudo
 element had to be on top of the other pseudo element which had a
 background color of the border.&lt;/p&gt;

&lt;h2&gt;New ideas&lt;/h2&gt;

&lt;p&gt;After coming across &lt;a href=&quot;http://cssnerd.com/2012/01/08/pure-css-tooltips-transparent-border-box-shadow/&quot;&gt;Gregor Adamsâ Pure CSS Tooltips blog post&lt;/a&gt;, I piggybacked off the idea of using linear gradients to create the triangle of the tooltip.&lt;/p&gt;

&lt;h2&gt;Finding a solution&lt;/h2&gt;

&lt;p&gt;It was a bit strange trying to figure out how to get a triangle with
borders only on two sides without extra surrounding
artifacts (watch what happens when we leave out background-repeat:
no-repeat in the CodePen at the bottomâ¦ weird!). Then came finding a
solution for the border around the tooltip. The border had to skip the
portion where the triangle tip sat.&lt;/p&gt;

&lt;p&gt;It wouldâve been cool if we could control dashed lines to be
able to change the lengths of the dashes or the space in between each
dash. Unfortunately we donât have that level of customization for
border-styleâs. Or if we could use some sort of border gradient with color stops,
but after trying that, I figured out that it didnât play well with border-radius. Then I thought to use some type of clipping
and I would even be able to angle my clip-path to fit better with my triangle tip! The path I figured worked best is outlined in black:
&lt;img src=&quot;https://i.imgur.com/qNTsmqh.jpg&quot; alt=&quot;Clip-path I used to remove part of tooltip border&quot;&gt;&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with clip-path, &lt;a href=&quot;http://bennettfeely.com/clippy/&quot;&gt;Bennett Feelyâs tool clippy&lt;/a&gt; helps visualize clip-path polygons and provides a good starting point with its dragging feature.&lt;/p&gt;

&lt;p data-height=&quot;780&quot; data-theme-id=&quot;0&quot; data-slug-hash=&quot;VLoEqa&quot;
data-default-tab=&quot;result&quot; data-user=&quot;acacheung&quot; class=&#39;codepen&#39;&gt;See the
Pen &lt;a href=&#39;http://codepen.io/acacheung/pen/VLoEqa/&#39;&gt;Transparent
tooltip with border&lt;/a&gt; by Amanda Cheung (&lt;a
href=&#39;http://codepen.io/acacheung&#39;&gt;@acacheung&lt;/a&gt;) on &lt;a
href=&#39;http://codepen.io&#39;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;script async src=&quot;//assets.codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Itâs not the &lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;DRYest&lt;/a&gt;, but it is flexible for tooltips that are multi-line as well
as tooltips that are longer in length. This also works with box-shadows, but clip-path would need to be adjusted and it can also handle transparency for the borders. Unfortunately at this time, Firefox and IE are not
supported because of how clip-path is being used.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Design sprints: what are they for?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/08/17/design-sprints-what-are-they-for" />
    <id>https://dockyard.com/blog/2015/08/17/design-sprints-what-are-they-for</id>
    <category term="process" label="Process"/><category term="business" label="Business"/><category term="design" label="Design"/><category term="design-process" label="Design Process"/><category term="discovery" label="Discovery"/><category term="planning" label="Planning"/><category term="workflow" label="Workflow"/>
    <published>2015-08-17 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Comparing how Design Sprints and Design Discovery can benefit your business</summary>
    <content type="html">&lt;p&gt;Design sprints at DockYard are based on the &lt;a href=&quot;http://www.gv.com/sprint/&quot;&gt;Google Ventures model&lt;/a&gt;, but with a shorter four-day duration. Design Discovery (the research and strategy phase that enables us test and plan out the entire application before proceeding with Visual Design and Engineering) lasts several weeks, and has a greater scope.&lt;/p&gt;

&lt;p&gt;While each process has its individual benefits, there are many that they share. In both cases, of Design Sprints and Discovery, we share work with the client early and often. This quick turnaround requires close attention and abstract thinking from the client (for example, evaluating an idea in sketch form rather than fully resolved designs). The benefit is that we course-correct quickly and eliminate alternatives early on.&lt;/p&gt;

&lt;p&gt;The difference is in the scope, end objective, and the deliverables. A design sprint can encompass a specific aspect of a product. It&amp;#39;s a highly collaborative and budget friendly way to spike on an idea. Design discovery is a holistic approach to goals and strategy for a product.&lt;/p&gt;

&lt;h2&gt;What sprints are good for&lt;/h2&gt;

&lt;p&gt;The purpose of a sprint is not to deliver a whole product, but a realistic model of a product experience. In a few cases a product experience may be small and focused enough to be encompassed entirely in the sprint. More likely, a design sprint focuses on a specific aspect of an application, and a single user story. &lt;/p&gt;

&lt;p&gt;A sprint might address a question like âhow would a new user sign up for your service on a mobile phone?â or âIn what ways could an existing customer use the web service youâre building in the course of their day?â A sprint is a rapid way to model and test specific situations, so that the product can be refined. In order to run a sprint, we make reasonable assumptions about a situation around your product, and then isolate, model, and test a them.&lt;/p&gt;

&lt;h2&gt;What a sprint looks like&lt;/h2&gt;

&lt;p&gt;Hereâs what a design sprint might look like at DockYard. Letâs imagine a product that helps customers know when a farm share they purchased would be delivered. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For the sprint, we would be focusing on sending and receiving messages between a delivery driver and a customer.&lt;/li&gt;
&lt;li&gt;We would only focus on the mobile view of this interaction (with an informed assumption that itâs the most convenient context for checking up on a delivery)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Monday: analyze the context&lt;/h3&gt;

&lt;p&gt;We kick off the sprint by analyzing the situation around the delivery. Who are our users? What problems do they encounter, and which ones can we help them solve? &lt;/p&gt;

&lt;p&gt;By the end of the day, we expect to diagram the portion of a customerâs experience receiving a delivery, and any actions they might take along the way.&lt;/p&gt;

&lt;h3&gt;Tuesday: sketch and define&lt;/h3&gt;

&lt;p&gt;On day two we take the workflow we already defined and turn it into a series of hand-sketched wireframes. In this process, additional details become clear and we move toward a standardized approach to similar screens. We define a series of messages between the customer and the delivery driver as the key interaction.&lt;/p&gt;

&lt;h3&gt;Wednesday: design and prototype&lt;/h3&gt;

&lt;p&gt;On day three, we translate the sketches into visual design. We design the key screens for the messaging interaction and create a minimal prototype to test drive how the messaging app might feel.&lt;/p&gt;

&lt;h3&gt;Thursday: test and refine&lt;/h3&gt;

&lt;p&gt;On the final day, we run several quick user tests with potential customers. We give test users a scenario like âyour delivery is coming - use the app to check on its arrival!â and observe how they interact with the prototype. We record any lessons learned - e.g. âuser assumed the button was inactiveâ.&lt;/p&gt;

&lt;p&gt;We then make any quick corrections based on the results of user testing (like making the button appear more active) and document what we learned as potential improvements or things to explore in the future. &lt;/p&gt;

&lt;p&gt;The result of a sprint in this case is a working prototype of messaging for our specific use case, and an understanding of what role this key interaction plays within the larger context of the app.&lt;/p&gt;

&lt;h2&gt;Picking between Sprint and Discovery&lt;/h2&gt;

&lt;p&gt;To decide which design process is right, consider the job each process does well. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/weKPZFU.jpg&quot; alt=&quot;A design sprint is like shining a focused flashlight&quot;&gt;
&lt;strong&gt;A sprint&lt;/strong&gt; quickly illuminates a specific aspect of your product, for example, a single user story. A series of sprints could produce a full picture, but at some point a Discovery approach becomes more effective.&lt;/p&gt;

&lt;p&gt;Sprints result in prototypes of your product or parts of it, and allow you to test things quickly. They are most efficient for solving shorter term business goals:  validating or iterating quickly on  a function of an application.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/qoYW3wC.jpg&quot; alt=&quot;Design Discovery can help illuminate the bigger picture&quot;&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Cave&quot;&gt;Original image source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discovery&lt;/strong&gt; usually requires more time and resources, but shows the larger picture.&lt;/p&gt;

&lt;p&gt;The combination of design discovery and visual design is a holistic process. It is a better investment in cases where youâre developing a new product, or have long term business goals and would like an investigation from all angles into how to achieve them.&lt;/p&gt;

&lt;p&gt;If you have a specific question in mind, &lt;a href=&quot;https://dockyard.com/contact/hire-us&quot;&gt;contact us&lt;/a&gt;. Weâll set up a short consultation meeting so we can help find out which process is right for you.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Applying the Adapter Pattern for Analytics</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/08/10/ember-metrics" />
    <id>https://dockyard.com/blog/2015/08/10/ember-metrics</id>
    <category term="addon" label="Addon"/><category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/>
    <published>2015-08-10 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Send data to multiple analytics integrations without re-implementing new API.</summary>
    <content type="html">&lt;p&gt;At DockYard, most (if not all) Ember apps we build for our clients require analytics in some form or other. For many of these apps, simply including the Google Analytics tracking script is sufficient. However, we&amp;#39;re noticing an increased interest in other analytics services such as Mixpanel or Kissmetrics for the more data minded clients.&lt;/p&gt;

&lt;p&gt;Including multiple services (typically we see about 3â5 different analytics in use) with different APIs leads to a lot of code duplication, which is less than ideal, and is generally a maintenance nightmare. I don&amp;#39;t know about you, but deleting repetitive code is one of my favorite things to doâââso &lt;a href=&quot;https://twitter.com/michaeldupuisjr&quot;&gt;Michael&lt;/a&gt; and I set out to build an Ember addon that would apply the adapter pattern to analytics.&lt;/p&gt;

&lt;p&gt;In this post, we&amp;#39;ll explore what the adapter pattern gives us, and demonstrate how to implement it in an easily extensible Ember addon so we can use one API to orchestrate multiple analytics services.&lt;/p&gt;

&lt;h2&gt;Introducing the ember-metrics addon&lt;/h2&gt;

&lt;p&gt;To install the addon:&lt;/p&gt;
&lt;div class=&quot;highlight sh &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ ember install ember-metrics
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can also find the &lt;a href=&quot;https://github.com/poteto/ember-metrics&quot;&gt;source on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The ember-metrics addon adds a simple metrics service and customized &lt;code&gt;LinkComponent&lt;/code&gt; to your app that makes it simple to send data to multiple analytics services without having to implement a new API each time.&lt;/p&gt;

&lt;p&gt;Using this addon, you can easily use bundled adapters for various analytics services, and one API to track events, page views, and more. When you decide to add another analytics service to your stack, all you need to do is add it to your configuration, and that&amp;#39;s it.&lt;/p&gt;

&lt;p&gt;With this addon, we wanted to make it super simple to write your own adapters for other analytics services too, so we set out to make it extensible and easily tested.&lt;/p&gt;

&lt;h2&gt;What is the Adapter Pattern?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/VpAAHrw.jpg&quot; alt=&quot;I heard you like adapters&quot;&gt;&lt;/p&gt;

&lt;p&gt;In a broad sense, the adapter pattern is about adapting between class and objects. Like its real world counterpart, the adapter is used as an interface, or bridge, between two objects.&lt;/p&gt;

&lt;p&gt;In the case of analytics, this is an excellent pattern for us to implement, because these services all have different APIs, but very similar intent. For example, to send an event to Google Analytics, you would use the analytics.js library like so:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;/** 
 * Where:
 * button is the category
 * click is the action
 * nav buttons is the label
 * 4 is the value
*/&lt;/span&gt;
ga(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;nav buttons&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt;);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;While in Mixpanel, you would track the same event like this:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;mixpanel.track(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Clicked Nav Button&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;value&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt; });
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And with Kissmetrics:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_kmq.push([&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Clicked Nav Button&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;value&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt; }]);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As you can probably tell, this gets repetitive really quickly, and becomes hard to maintain when your boss or client wants to update something as simple as the event name across these services.&lt;/p&gt;

&lt;h2&gt;Applying the Adapter Pattern&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/azNt3ri.png&quot; alt=&quot;Diagram from https://sourcemaking.com/design_patterns/adapter&quot;&gt;&lt;/p&gt;

&lt;p&gt;We generally have a few players in the adapter pattern: the client, the adapter (or wrapper), and the adaptee.&lt;/p&gt;

&lt;p&gt;For ember-metrics, the client is our &lt;code&gt;Ember.Service&lt;/code&gt;, the adapter is the adapter created for each analytics service, and the adaptee is the analytics library&amp;#39;s API.&lt;/p&gt;

&lt;p&gt;Each analytics service has its own adapter that implements a standard contract to impedance match the analytics library&amp;#39;s API to the &lt;code&gt;Ember.Service&lt;/code&gt; that is responsible for conducting all of the analytics in unison.&lt;/p&gt;

&lt;h2&gt;Using ember-metrics&lt;/h2&gt;

&lt;p&gt;The addon is first setup by configuring it in &lt;code&gt;config/environment&lt;/code&gt;, then injected into any Object registered in the container that you wish to track.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;module.&lt;span class=&quot;function&quot;&gt;exports&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(environment) {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; ENV = {
    &lt;span class=&quot;key&quot;&gt;metricsAdapters&lt;/span&gt;: [
      { &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;GoogleAnalytics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;config&lt;/span&gt;: { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;UA-XXXX-Y&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; } },
      { &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Mixpanel&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;config&lt;/span&gt;: { &lt;span class=&quot;key&quot;&gt;token&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;xxx&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; } }
    ]
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then, you can call a &lt;code&gt;trackPage&lt;/code&gt; event across all your analytics services like so, using the &lt;code&gt;metrics&lt;/code&gt; service:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  &lt;span class=&quot;key&quot;&gt;metrics&lt;/span&gt;: Ember.inject.service(),

  activate() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._trackPage();
  },

  _trackPage() {
    Ember.run.scheduleOnce(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;afterRender&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, () =&amp;gt; {
      const page = document.location.href;
      const title = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.routeName;

      get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;metrics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).trackPage({ page, title });
    });
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you wish to only call a single service, just specify its name as the first argument:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// only invokes the `trackPage` method on the `GoogleAnalyticsAdapter`&lt;/span&gt;
metrics.trackPage(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;GoogleAnalytics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;My Awesome App&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; });
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is clearly a much cleaner implementation, as we can now use one API to invoke across all services we want to use in our app.&lt;/p&gt;

&lt;h2&gt;Implementing the Adapter Pattern in ember-metrics&lt;/h2&gt;

&lt;p&gt;The service &lt;code&gt;metrics&lt;/code&gt; is the heart of the addon, and is responsible for orchestrating event tracking across all analytics that have been activated.&lt;/p&gt;

&lt;h3&gt;Setting up addon configuration&lt;/h3&gt;

&lt;p&gt;A simple pattern for passing configuration from the consuming app&amp;#39;s &lt;code&gt;config/environment&lt;/code&gt; to the addon is through an initializer:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; config from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../config/environment&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(_container, application) {
  const { metricsAdapters = {} } = config;

  application.register(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;config:metrics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, metricsAdapters, { &lt;span class=&quot;key&quot;&gt;instantiate&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt; });
  application.inject(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;service:metrics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;metricsAdapters&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;config:metrics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
}

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;metrics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  initialize
};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This lets us access the configuration POJO from within the metrics service by retrieving the &lt;code&gt;metricsAdapter&lt;/code&gt; property when the service is created.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Service.extend({
  &lt;span class=&quot;key&quot;&gt;_adapters&lt;/span&gt;: {},

  init() {
    const adapters = Ember.getWithDefault(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;metricsAdapters&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, Ember.A([]));
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super(...&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.activateAdapters(adapters);
  },

  activateAdapters(adapterOptions = []) {
    const cachedAdapters = Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;_adapters&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    const activatedAdapters = {};

    adapterOptions.forEach((adapterOption) =&amp;gt; {
      const { name } = adapterOption;
      let adapter;

      &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (cachedAdapters[name]) {
        warn(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;[ember-metrics] Metrics adapter &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{name} has already been activated.&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
        adapter = cachedAdapters[name];
      } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
        adapter = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._activateAdapter(adapterOption);
      }

      Ember.set(activatedAdapters, name, adapter);
    });

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Ember.set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;_adapters&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, activatedAdapters);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With the retrieved configuration, we then call the service&amp;#39;s &lt;code&gt;activateAdapters&lt;/code&gt; method in order to retrieve the adapter(s) from the addon or locally, then caching them in the service so they can be looked up later easily.&lt;/p&gt;

&lt;p&gt;Activating an adapter simply calls &lt;code&gt;create&lt;/code&gt; on the looked up adapter (which inherits from &lt;code&gt;Ember.Object&lt;/code&gt;) and passes along any analytics specific configuration such as API keys.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_activateAdapter(adapterOption = {}) {
  const metrics = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;;
  const { name, config } = adapterOption;

  const Adapter = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._lookupAdapter(name);
  assert(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;[ember-metrics] Could not find metrics adapter &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{name}.&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;, Adapter);

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Adapter.create({ metrics, config });
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Because we&amp;#39;ve also implemented caching, we can safely call &lt;code&gt;activateAdapters&lt;/code&gt; without having to re-instantiate already activated adapters, which allows us to defer the initialization of these analytics if (for example) we need to dynamically retrieve a property from one of our models:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  &lt;span class=&quot;key&quot;&gt;metrics&lt;/span&gt;: Ember.inject.service(),
  afterModel(model) {
    const metrics = Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;metrics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    const id = Ember.get(model, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;googleAnalyticsKey&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

    metrics.activateAdapters([
      { &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;GoogleAnalytics&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;config&lt;/span&gt;: { id } }
    ]);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Leveraging the container and resolver&lt;/h3&gt;

&lt;p&gt;Then, leveraging the Ember container and conventions around the &lt;a href=&quot;https://github.com/ember-cli/ember-resolver&quot;&gt;ember-resolver&lt;/a&gt;, we can lookup adapters from the addon first, and then fallback to locally created adapters.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_lookupAdapter(adapterName = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) {
  const container = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (isNone(container)) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;;
  }

  const dasherizedAdapterName = dasherize(adapterName);
  const availableAdapter = container.lookupFactory(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;ember-metrics&lt;span class=&quot;error&quot;&gt;@&lt;/span&gt;metrics-adapter:&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{dasherizedAdapterName}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
  const localAdapter = container.lookupFactory(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;metrics-adapter:&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{dasherizedAdapterName}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
  const adapter = availableAdapter ? availableAdapter : localAdapter;

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; adapter;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Invoking adapter methods from the service&lt;/h3&gt;

&lt;p&gt;Now that our service can access both local and addon adapters, we can invoke methods across activated adapters like so:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;identify(...args) {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.invoke(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;identify&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, ...args);
},

alias(...args) {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.invoke(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, ...args);
},

trackEvent(...args) {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.invoke(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, ...args);
},

trackPage(...args) {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.invoke(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;trackPage&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, ...args);
},

invoke(methodName, ...args) {
  const adaptersObj = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;_adapters&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const adapterNames = Object.keys(adaptersObj);

  const adapters = adapterNames.map((adapterName) =&amp;gt; {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; get(adaptersObj, adapterName);
  });

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (args.length &amp;gt; &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;) {
    let [ adapterName, options ] = args;
    const adapter = get(adaptersObj, adapterName);

    adapter[methodName](options);
  } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
    adapters.forEach((adapter) =&amp;gt; {
      adapter[methodName](...args);
    });
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Creating Adapters for the Addon&lt;/h2&gt;

&lt;p&gt;With the service implemented, we can now create a &lt;a href=&quot;https://github.com/poteto/ember-metrics/blob/0.1.2/addon/metrics-adapters/base.js&quot;&gt;base adapter class&lt;/a&gt; that all adapters extend from. This is mainly so we can assert that the adapter&amp;#39;s &lt;code&gt;init&lt;/code&gt; and &lt;code&gt;willDestroy&lt;/code&gt; hooks are implemented, and to give it a nicer output in the console through overriding the &lt;code&gt;toString&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;re not already familiar with the Ember Object model, the &lt;code&gt;init&lt;/code&gt; method is called whenever an &lt;code&gt;Ember.Object&lt;/code&gt; is instantiated through &lt;code&gt;Ember.Object.create()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can thus rely on this knowledge that &lt;code&gt;init&lt;/code&gt; will always be called on object instantiation to pass in configuration to the analytics, and to call its setup. Typically, an analytics service will create a script tag through JavaScript, and asynchronously load its library from some CDN.&lt;/p&gt;

&lt;p&gt;For example, here&amp;#39;s the &lt;a href=&quot;https://github.com/poteto/ember-metrics/blob/0.1.2/addon%2Fmetrics-adapters%2Fgoogle-analytics.js&quot;&gt;Google Analytics adapter&lt;/a&gt; that&amp;#39;s bundled with the addon.&lt;/p&gt;

&lt;h3&gt;Enhancing the developer experience with blueprints&lt;/h3&gt;

&lt;p&gt;One of my favorite parts of ember-cli are its generators. Using blueprints, we can easily extend the cli commands to generate new metrics adapters using:&lt;/p&gt;
&lt;div class=&quot;highlight sh &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ ember generate metrics-adapter foo-bar
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This creates &lt;code&gt;app/metrics-adapters/foo-bar.js&lt;/code&gt; and a unit test at &lt;code&gt;tests/unit/metrics-adapters/foo-bar-test.js&lt;/code&gt;. You can take a closer look at these blueprints &lt;a href=&quot;https://github.com/poteto/ember-metrics/tree/0.1.2/blueprints&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With these conventions in place, it&amp;#39;s now trivial for consuming app developers to add new adapters to work alongside bundled adapters. And when they feel that an adapter they&amp;#39;ve built is ready to be shared with the community, they only need open a pull request to have that adapter included in the addon.&lt;/p&gt;

&lt;p&gt;At some point in the future, it would make sense for each adapter to have its own repo and npm module, but to keep things simple, we&amp;#39;ve placed them within the addon.&lt;/p&gt;

&lt;p&gt;Now we can easily send data to multiple analytics integrations through one API, DRYing up our code and making it more maintainable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post also appears on &lt;a href=&quot;https://medium.com/the-ember-way/applying-the-adapter-pattern-for-analytics-in-ember-js-apps-29448cbcedf3&quot;&gt;Medium in longform&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Polymorphic URLs in Ember</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/08/08/polymorphic-urls-in-ember" />
    <id>https://dockyard.com/blog/2015/08/08/polymorphic-urls-in-ember</id>
    <category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/>
    <published>2015-08-08 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Ember makes it easy to consume polymorphic records, assuming you have
the following data retrieved from your server:&lt;/p&gt;
&lt;div class=&quot;highlight json &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [
    {
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hooman&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;relationships&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {
        &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pet&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {
          &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
          }
        }
      }
    }, {
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hooman&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;relationships&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {
        &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pet&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {
          &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dog&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;
          }
        }
      }
    }
  ]
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s put aside my contrived data model for a minute, the point is that
in this set the &lt;code&gt;pet&lt;/code&gt; relationship for the &lt;code&gt;hooman&lt;/code&gt; can be of type
&lt;code&gt;cat&lt;/code&gt; or &lt;code&gt;dog&lt;/code&gt;. We can handle this in Ember Data by first
creating a &lt;code&gt;pet&lt;/code&gt; model:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; DS from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  attr,
  belongsTo,
  Model
} = DS;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Model.extend({
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;hooman&lt;/span&gt;: belongsTo(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hooman&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) 
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then in the &lt;code&gt;hooman&lt;/code&gt; model:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; DS from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  attr,
  belongsTo,
  Model
} = DS;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Model.extend({
  &lt;span class=&quot;key&quot;&gt;pet&lt;/span&gt;: belongsTo(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pet&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;polymorphic&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt; })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This will instruct the relationship to look at the &lt;code&gt;type&lt;/code&gt; property to
determine the model type. You can then access through the &lt;code&gt;pet&lt;/code&gt;
property:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;get(hooman, &amp;#39;pet&amp;#39;) // &amp;lt;cat-model&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ok, this was probably review for some people. I recently ran into an
issue where I needed to do a &lt;code&gt;link-to&lt;/code&gt; for a polymorphic relationship. Using
our same example, I would have done:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{link-to hooman.pet.name &#39;pet&#39; hooman.pet}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The router would be setup as:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// you should make this one of the last routes&lt;/span&gt;
&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pet&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;path&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/:pet_type/:pet_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; });
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When we are using &lt;code&gt;link-to&lt;/code&gt; there really isn&amp;#39;t an issue as Ember will
just use the model passed in as the model. But we want a nicely
formatted URL. Ideally if we are passing in a &lt;code&gt;cat&lt;/code&gt; pet we would
end up with the url: &lt;code&gt;/cats/2&lt;/code&gt; and if we are passing in a &lt;code&gt;dog&lt;/code&gt;
pet we&amp;#39;d get &lt;code&gt;/dogs/5&lt;/code&gt; and both would be processed by the &lt;code&gt;pet&lt;/code&gt;
route and template (of course we&amp;#39;d have to make sure they both respond
to the same properties).&lt;/p&gt;

&lt;p&gt;To get this we can override the
&lt;a href=&quot;http://emberjs.com/api/classes/Ember.Route.html#method_serialize&quot;&gt;&lt;code&gt;serialize&lt;/code&gt;&lt;/a&gt; function in our &lt;code&gt;pet&lt;/code&gt;
route. &lt;code&gt;serialize&lt;/code&gt; is used to parse information out of your model to
render the URL associated. It is simple enough to do what we want:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  get,
  Route
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Route.extend({
  serialize(model) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; {
      &lt;span class=&quot;key&quot;&gt;pet_type&lt;/span&gt;: model.constructor.modelName,
      &lt;span class=&quot;key&quot;&gt;pet_id&lt;/span&gt;: get(model, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    };
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now the &lt;code&gt;link-to&lt;/code&gt; will render how we&amp;#39;d expect. Well, mostly. With this
we end up with singular route names: &lt;code&gt;/dog/5&lt;/code&gt; instead of &lt;code&gt;/dogs/5&lt;/code&gt; for
example. We need to pluralize.&lt;/p&gt;

&lt;p&gt;Because we&amp;#39;re using Ember Data the
&lt;a href=&quot;https://github.com/stefanpenner/ember-inflector&quot;&gt;ember-inflector&lt;/a&gt; library is pulled
in automatically. Let&amp;#39;s use that:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  get,
  Route,
  &lt;span class=&quot;key&quot;&gt;String&lt;/span&gt;: { pluralize }
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Route.extend({
  serialize(model) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; {
      &lt;span class=&quot;key&quot;&gt;pet_type&lt;/span&gt;: pluralize(model.constructor.modelName),
      &lt;span class=&quot;key&quot;&gt;pet_id&lt;/span&gt;: get(model, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    };
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we get &lt;code&gt;/dogs/5&lt;/code&gt;. If you are using a different type that does not
pluralize nicely (for example &lt;code&gt;person&lt;/code&gt; =&amp;gt; &lt;code&gt;persons&lt;/code&gt; instead of &lt;code&gt;people&lt;/code&gt;)
then check out the &lt;a href=&quot;https://github.com/stefanpenner/ember-inflector&quot;&gt;ember-inflector README for details on how to add the
pluralized types you
need&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is great, except if someone visits the URL directly instead of
clicking on a link. Let&amp;#39;s add support for that.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const {
  get,
  Route,
  &lt;span class=&quot;key&quot;&gt;String&lt;/span&gt;: { pluralize, singularize }
} = Ember;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Route.extend({
  model(params) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.store.find(singularize(params.pet_type), params.pet_id);
  },
  serialize(model) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; {
      &lt;span class=&quot;key&quot;&gt;pet_type&lt;/span&gt;: pluralize(model.constructor.modelName),
      &lt;span class=&quot;key&quot;&gt;pet_id&lt;/span&gt;: get(model, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    };
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There we go! Because the URL segment was pluralized we used
&lt;code&gt;singularize&lt;/code&gt; to force the type back to what the &lt;code&gt;store&lt;/code&gt; expects. I hope
this helps you.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Suave Up Your Code</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/08/07/suave-up-your-code" />
    <id>https://dockyard.com/blog/2015/08/07/suave-up-your-code</id>
    <category term="addon" label="Addon"/><category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/>
    <published>2015-08-07 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Estelle DeBlois</name></author>
    <summary></summary>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;/swÃ¤v/
&amp;quot;Smooth in texture, performance, or style&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You may have heard of this thing called &lt;a href=&quot;https://github.com/dockyard/ember-suave&quot;&gt;&lt;code&gt;ember-suave&lt;/code&gt;&lt;/a&gt;. It&amp;#39;s a handy Ember CLI addon that &lt;a href=&quot;https://twitter.com/rwjblue&quot;&gt;Robert Jackson&lt;/a&gt; and I put together a few months ago to enforce code style consistency across teams and projects. &lt;em&gt;If you&amp;#39;re wondering how the addon got its name, just ask Rob. He was feeling inspired that day.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ember-suave&lt;/code&gt; uses &lt;a href=&quot;http://jscs.info/&quot;&gt;JSCS&lt;/a&gt; to ensure that your code conforms to a set of code style rules, and fails your tests if it doesn&amp;#39;t.&lt;/p&gt;

&lt;p&gt;Unlike &lt;a href=&quot;http://jshint.com/&quot;&gt;JSHint&lt;/a&gt;, which aims to detect errors and potential problems in your JavaScript code, JSCS is a code style linter. In other words, it is the tool you need to make sure all those hearty debates on tabs vs. spaces don&amp;#39;t go to waste, and that whatever style guide you managed to settle on within your team can be enforced and maintained.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://imgs.xkcd.com/comics/code_quality.png&quot; alt=&quot;code quality&quot;&gt;&lt;/p&gt;

&lt;h2&gt;The first rule of &lt;code&gt;ember-suave&lt;/code&gt; is to install &lt;code&gt;ember-suave&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;With JSCS, you control which rules to enable within a project by specifying the rule names and options in a &lt;code&gt;.jscsrc&lt;/code&gt; file, which may look something like this:&lt;/p&gt;
&lt;div class=&quot;highlight json &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;esnext&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;true&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;disallowSpacesInsideParentheses&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;true&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;disallowTrailingComma&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;true&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;requireBlocksOnNewline&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;true&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;validateIndentation&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Assuming you&amp;#39;re adhering to a single style guide for all your projects, the configuration would be the same everywhere. &lt;code&gt;ember-suave&lt;/code&gt; exists so you don&amp;#39;t have to recreate and maintain that file in every project. The addon comes bundled with a default configuration file that&amp;#39;s nicely tucked away within the addon itself so you don&amp;#39;t have to muck with it.&lt;/p&gt;

&lt;p&gt;Using the addon consists simply of running &lt;code&gt;ember install ember-suave&lt;/code&gt;, then monitoring your console for error messages during development.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ember-suave&lt;/code&gt; also creates a test for each file it finds in your project, so that you can enforce the code style rules as part of your continuous integration flow, and fail any builds that don&amp;#39;t comply.&lt;/p&gt;

&lt;h2&gt;You don&amp;#39;t rule &lt;code&gt;ember-suave&lt;/code&gt;. &lt;code&gt;ember-suave&lt;/code&gt; rules you.&lt;/h2&gt;

&lt;p&gt;Actually, that&amp;#39;s not exactly true. The addon was made to be quite configurable.&lt;/p&gt;

&lt;p&gt;You can use it as is, or you can tweak which rules to enable or disable. To configure &lt;code&gt;ember-suave&lt;/code&gt;, simply create a &lt;code&gt;.jscsrc&lt;/code&gt; file at the root of your project, listing just those rules that you want to modify. The addon will take care of merging your custom configuration with its own. For example, the following &lt;code&gt;.jscsrc&lt;/code&gt; file would set a different indentation style from the default of 2 spaces. It would also disable the &lt;code&gt;requireSpaceBetweenArguments&lt;/code&gt; rule and instruct JSCS to ignore all the files in the &lt;code&gt;fixtures&lt;/code&gt; folder:&lt;/p&gt;
&lt;div class=&quot;highlight json &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;validateIndentation&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;requireSpaceBetweenArguments&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;excludeFiles&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fixtures/**&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Need more suaveness?&lt;/h2&gt;

&lt;p&gt;If you have a particular code style need but no rule exists in JSCS yet, you can easily roll your own. In fact, &lt;code&gt;ember-suave&lt;/code&gt; ships with a few &lt;a href=&quot;https://github.com/dockyard/ember-suave/tree/master/lib/rules&quot;&gt;custom rules&lt;/a&gt; already. Let&amp;#39;s take a look at the rule that disallows the use of &lt;code&gt;var&lt;/code&gt;, preferring &lt;code&gt;const&lt;/code&gt; and &lt;code&gt;let&lt;/code&gt; instead:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// lib/rules/disallow-var.js&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; assert = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

module.&lt;span class=&quot;function&quot;&gt;exports&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {};

module.exports.prototype = {
  &lt;span class=&quot;function&quot;&gt;configure&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(option) {
    assert(option === &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.getOptionName() + &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; requires a true value&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  },

  &lt;span class=&quot;function&quot;&gt;getOptionName&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;disallowVar&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
  },

  &lt;span class=&quot;function&quot;&gt;check&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(file, errors) {
    file.iterateNodesByType(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;VariableDeclaration&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(node) {
      node.declarations.forEach(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(declaration) {
        &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (declaration.parentNode.kind === &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) {
          errors.add(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Variable declarations should use `let` or `const` not `var`&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, node.loc.start);
        }
      });
    });
  }
};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A rule will always have these three methods: &lt;code&gt;configure&lt;/code&gt;, &lt;code&gt;getOptionName&lt;/code&gt;, and &lt;code&gt;check&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;getOptionName&lt;/code&gt; is self-explanatory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;configure&lt;/code&gt; is where you assert that a rule has been configured properly in a given &lt;code&gt;.jscsrc&lt;/code&gt; file. For example, this would not pass the assert, since the value has to be &lt;code&gt;true&lt;/code&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight json &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;disallowVar&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Feeling suave today!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;check&lt;/code&gt; is where all the magic happens. Any given file would first get parsed by JSCS into an AST (Abstract Syntax Tree) before you can analyze its content. You can use the &lt;code&gt;file&lt;/code&gt; object that is passed into the &lt;code&gt;check&lt;/code&gt; function to iterate over specific nodes of the tree. For this custom rule, we are looking for any variables that were declared using &lt;code&gt;var&lt;/code&gt;. If such a declaration is found, we add to the errors object, passing in an error message and the position of the offending code. This is what you would see in the console if you tried using &lt;code&gt;var&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;disallowVar: Variable declarations should use `let` or `const` not `var` at router.js :
     2 |import config from &#39;./config/environment&#39;;
     3 |
     4 |var Router = Ember.Router.extend({
--------^
     5 |  location: config.locationType
     6 |});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Confused about the node types and what to look for? It&amp;#39;s actually not very complicated. You can navigate over to &lt;a href=&quot;http://esprima.org/demo/parse.html&quot;&gt;Esprima&lt;/a&gt;, the parser used by JSCS, enter a code snippet into the &lt;a href=&quot;http://esprima.org/demo/parse.html&quot;&gt;Online Parsing Tool&lt;/a&gt;, and see what the corresponding tree looks like.&lt;/p&gt;

&lt;p&gt;For instance, &lt;code&gt;var color = &amp;#39;blue&amp;#39;;&lt;/code&gt; will generate the following syntax tree:&lt;/p&gt;
&lt;div class=&quot;highlight json &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Program&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [
    {
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;VariableDeclaration&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;declarations&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: [
        {
          &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;VariableDeclarator&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
          &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
          },
          &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: {
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Literal&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
            &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;&#39;blue&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
          }
        }
      ],
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    }
  ]
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now you can see why we were checking for nodes of type &lt;code&gt;VariableDeclaration&lt;/code&gt;, and why we checked whether they were declared with &lt;code&gt;var&lt;/code&gt; using &lt;code&gt;declaration.parentNode.kind === &amp;#39;var&amp;#39;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also refer to the many &lt;a href=&quot;https://github.com/jscs-dev/node-jscs/tree/master/lib/rules&quot;&gt;rules&lt;/a&gt; that already exist in JSCS as you write your own.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ember-suave&lt;/code&gt; started as an internal need at DockYard to enforce our &lt;a href=&quot;https://github.com/dockyard/styleguides/blob/master/javascript.md&quot;&gt;style guide&lt;/a&gt; in a painless, automatable way.&lt;/p&gt;

&lt;p&gt;That said, the addon was built such that anyone can take advantage of the tool. If you start a new Ember CLI project, I recommend you check it out. And if you&amp;#39;re thinking of dropping it into an existing project, but fear that the sheer amount of potential error messages would be too time-consuming to address all at once, you can always start by disabling all the rules, then re-enable them one rule at a time. Or you could exclude specific folders; whatever helps bring more suaveness to your code.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building json-api endpoints with Phoenix</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/08/05/building-json-api-endpoints-with-phoenix" />
    <id>https://dockyard.com/blog/2015/08/05/building-json-api-endpoints-with-phoenix</id>
    <category term="phoenix" label="Phoenix"/><category term="ember" label="Ember.js"/><category term="elixir" label="Elixir"/>
    <published>2015-08-05 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I&amp;#39;m currently building a &lt;a href=&quot;http://www.phoenixframework.org/&quot;&gt;Phoenix&lt;/a&gt; backend API that is being consumed by
&lt;a href=&quot;http://emberjs.com/blog/2015/06/18/ember-data-1-13-released.html&quot;&gt;Ember Data
1.13&lt;/a&gt; which uses &lt;a href=&quot;http://jsonapi.org/&quot;&gt;JSON API&lt;/a&gt;. Here is how I 
hooked everything up.&lt;/p&gt;

&lt;h2&gt;Configuration&lt;/h2&gt;

&lt;p&gt;You first need to tell Phoenix that it should accept &lt;code&gt;json-api&lt;/code&gt; format.
I created a new
&lt;a href=&quot;http://hexdocs.pm/phoenix/Phoenix.Router.html#pipeline/2&quot;&gt;&lt;code&gt;pipeline/2&lt;/code&gt;&lt;/a&gt;
for the API:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# web/router.ex

pipeline :api do
  plug :accepts, [&amp;quot;json-api&amp;quot;]
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We next need to add the corresponding MIME type:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# config/config.exs

config :plug, :mimes, %{
  &amp;quot;application/vnd.api+json&amp;quot; =&amp;gt; [&amp;quot;json-api&amp;quot;]
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we have to force Plug to recompile. To do this we have to &lt;code&gt;touch&lt;/code&gt; a
file in the dependency. This may seem a little odd but the &lt;a href=&quot;https://github.com/elixir-lang/plug/blob/0118337b990aa2109a7b9152ea1e244a37c7dd07/lib/plug/mime.ex#L5-L16&quot;&gt;documentation
recommends this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt; touch deps/plug/mix.exs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt; mix deps.compile plug&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I like to namespace my APIs so I created a scope and piped it through my
&lt;code&gt;api&lt;/code&gt; pipeline:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# web/router.ex

scope &amp;quot;api/v1&amp;quot;, MyApp do
  pipe_through :api
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I declare all of my API routes in that scope.&lt;/p&gt;

&lt;h2&gt;Emitting&lt;/h2&gt;

&lt;p&gt;To emit json-api responses I am currently using
&lt;a href=&quot;https://github.com/AgilionApps/ja_serializer&quot;&gt;ja_serializer&lt;/a&gt;. The
author has indicated that some big changes are likely to better align
with Phoenix conventions but for now this is the only serializer I am
aware of. The README explains how to serialize, it is pretty simple. For
example, to serialize a collection form an &lt;code&gt;index&lt;/code&gt; action:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def index(conn, _) do
  foos = Repo.all(Foo)
  |&amp;gt; MyApp.FooSerializer.format(conn)

  json(conn, foos)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You may wish to use Views but I&amp;#39;ve opted not to.&lt;/p&gt;

&lt;p&gt;The serializer itself would look like:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# serializers/foo_serializer.ex

defmodule MyApp.FooSerializer do
  use JaSerializer

  serialize &amp;quot;foo&amp;quot; do
    attributes [
      &amp;quot;name&amp;quot;,
      &amp;quot;description&amp;quot;
    ]
  end
end 
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can embed relationships as well, check out the project for more
deatils.&lt;/p&gt;

&lt;h2&gt;Consuming&lt;/h2&gt;

&lt;p&gt;Ember Data not only expects to get JSON API format but also sends JSON
API format back to the server when you are creating or updating. The
attributes keys come in hyphenated and everythig is nested under &lt;code&gt;&amp;quot;data&amp;quot; =&amp;gt;
&amp;quot;attributes&amp;quot;&lt;/code&gt;. Here is how I made life easier for mmyself.&lt;/p&gt;

&lt;p&gt;I first wrote a new plug that deserializes all params that are coming in
by forcing hyphenated keys to underscore format. It works recursively on
all keys and produces a new params object that is Phoenix friendly. Here
is the code:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# web/plugs/deserialize.ex

defmodule MyApp.DeserializePlug do
  def init(options) do
    options
  end

  def call(%Plug.Conn{params: %{&amp;quot;format&amp;quot; =&amp;gt; &amp;quot;json-api&amp;quot;}, method: &amp;quot;POST&amp;quot;}=conn, _opts) do
    result = _deserialize(conn)
  end

  def call(%Plug.Conn{params: %{&amp;quot;format&amp;quot; =&amp;gt; &amp;quot;json-api&amp;quot;}, method: &amp;quot;PUT&amp;quot;}=conn, _opts) do
    _deserialize(conn)
  end

  def call(%Plug.Conn{params: %{&amp;quot;format&amp;quot; =&amp;gt; &amp;quot;json-api&amp;quot;}, method: &amp;quot;PATCH&amp;quot;}=conn, _opts) do
    _deserialize(conn)
  end

  def call(conn, _opts), do: conn

  defp _deserialize(%Plug.Conn{}=conn) do
    Map.put(conn, :params, _deserialize(conn.params))
  end

  defp _deserialize(%{}=params) do
    Enum.into(params, %{}, fn({key, value}) -&amp;gt; { _underscore(key), _deserialize(value) } end)
  end

  defp _deserialize(value), do: value
  defp _underscore(key), do: String.replace(key, &amp;quot;-&amp;quot;, &amp;quot;_&amp;quot;)
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I then added this custom plug to my &lt;code&gt;api&lt;/code&gt; pipeline:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# web/router.ex

pipeline :api do
  plug :accepts, [&amp;quot;json-api&amp;quot;]
  plug MyApp.DeserializePlug
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, JSON API&amp;#39;s schema is verbose and I didn&amp;#39;t want to have to deal with this in my actions,
Elixir&amp;#39;s pattern matching is perfect for this. I capture all the
attributes into &lt;code&gt;params&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def create(conn, %{&amp;quot;data&amp;quot; =&amp;gt; %{&amp;quot;attributes&amp;quot; =&amp;gt; params}, &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;json-api&amp;quot;}) do
  # create action now has
  # a &amp;quot;params&amp;quot; object with all the
  # attribute date from the client request
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We can even guard the action for JSON API specific types.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Getting JSON API working with Phoenix takes a few hoops to jump through, but
hopefully this helps you get up and running.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Paving Desire Paths</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/08/03/paving-desire-paths" />
    <id>https://dockyard.com/blog/2015/08/03/paving-desire-paths</id>
    <category term="observations" label="Observations"/><category term="design" label="Design"/><category term="design-thinking" label="Design Thinking"/><category term="user-experience" label="User Experience"/>
    <published>2015-08-03 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Tim Walsh</name></author>
    <summary>Recognizing preferred interactions of users</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/HCN4mDr.jpg?1&quot; alt=&quot;A desire path&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://flic.kr/p/5kDxUt&quot;&gt;Desire path&lt;/a&gt; by &lt;a href=&quot;https://flic.kr/ps/2gcpv7&quot;&gt;wetwebwork &lt;/a&gt; is licensed under &lt;a href=&quot;http://creativecommons.org/licenses/by/2.0/&quot;&gt;CC BY 2.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently came across the term Desire Paths while reading &lt;a href=&quot;http://amzn.com/1592535879&quot;&gt;The Universal Principles of Design&lt;/a&gt;. Desire Paths are signs of use or wear indicating a preferred method of interaction. Most often they can be seen as shortcuts or diversions from the expected route. Some have clear intentions, like the picture shown above. This one in particular provides a direct route to the other side of the park. &lt;/p&gt;

&lt;p&gt;Desire paths are helpful in understanding users. They provide unbiased, concrete evidence into usersâ preferred activity. But they also serve as a reminder about how we may have assumed their activity incorrectly. &lt;/p&gt;

&lt;p&gt;Letâs consider this scenario. You are a park planner. Your job involves figuring out where the trees, benches, and other park related objects go. Your goal is to have people use and interact with the park. Adding paths seems like a direct means to accomplish this objective. âI add paths, and people will use them to get where they need to go.â This follows a sort of âbuild it and they will comeâ logic.&lt;/p&gt;

&lt;p&gt;However this is not the best practice. What the park planner lacks in this scenario is any insight from users. Are the paths they&amp;#39;re designing really the best, most efficient routes through the park? Is that what users are even after? Maybe users simply want to meander and walk leisurely. Or maybe they use it for running. In any case, the park planner likely forgot to holistically consider the user base.&lt;/p&gt;

&lt;p&gt;Imagine instead they had planted grass and trees and waited a year or so for users to interact with the park. The result would be a network of natural paths created and defined by users. At this point, the park planner could then pave all the paths, feeling confident that the decisions were justified. This method of design is not only efficient, it is also affordable. A little bit of research can save on both time and money, all while creating a better experience. Â &lt;/p&gt;

&lt;p&gt;Desire paths are a design principle that can be applicable to any industry. Letâs take a look at Twitter. During its humble beginnings Twitter was a pretty basic service, offering not much besides a stream of updates from your friends. Over time, Twitter noticed some unexpected trends appearing in their service. People who wanted to reply to someone else would simply direct it at them with an @ symbol and then enter the user&amp;#39;s name. (i.e. @Bill). As more people began doing this, Twitter began to take notice, eventually integrating it into the service. The same thing happened with hashtags and group discussions. &lt;/p&gt;

&lt;p&gt;What Twitter did correctly was first come up with a solid concept and deploy it, paying close attention to their user base. They provided the infrastructure, then sat back and watched as people used it to their liking. From this, natural trends began to emerge, paths became visible, and soon features were being defined - not by the service, but by the users.&lt;/p&gt;

&lt;p&gt;This is precisely the value of desire paths. They can reveal better solutions for users. Ones that werenât even considered in the first place. So take note of desire paths, learn from them, and build on top of them. Itâs your users talking, time to listen. &lt;/p&gt;
</content>
  </entry><entry>
    <title>Taking Advantage of Time Limitations In Design</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/07/31/taking-advantage-of-time-limitations-in-design" />
    <id>https://dockyard.com/blog/2015/07/31/taking-advantage-of-time-limitations-in-design</id>
    <category term="design-thinking" label="Design Thinking"/><category term="user-experience" label="User Experience"/><category term="design" label="Design"/><category term="design-process" label="Design Process"/>
    <published>2015-07-31 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Patrick Branigan</name></author>
    <summary>Three simple practices for designing in a limited amount of time</summary>
    <content type="html">&lt;p&gt;There may not be a larger, more persistent constraint in design than the notion of time. Time haunts us with its impact on our projects. There exists a constant struggle to come to terms with the fact that time is never going to be on our side. How often do we find ourselves saying, âIf only I had more timeâ¦â? &lt;/p&gt;

&lt;p&gt;One of the primary effects of time on design is its ability to force a result. The limiting nature of time forces us to be persistent and show progress. Yet persistence and progress are important parts of creating meaningful work. Designers need to focus on how to best use time weâre allotted because we donât seem to notice just how beneficial time can be when itâs limited.&lt;/p&gt;

&lt;p&gt;The following three practices can always help in delivering a successful design. They add clarity to your work but are especially valuable in the sense that they donât require a massive amount of time in the design process.&lt;/p&gt;

&lt;h2&gt;The grid&lt;/h2&gt;

&lt;p&gt;A grid can be constructed promptly and is very flexible in solving our visual design goals. Grids allow us to control the proximity of elements, therefore providing balance, arrangement and other visual suggestion to users. For a user, this can make a design attractive. How attractive something is, regardless of its usability, will inevitably leave a positive impression on users. This is loosely derived from a principle known as the aesthetic-usability effect. Content is an important driver in design but the grid assists in providing clarity and consistency in digesting content. &lt;/p&gt;

&lt;h2&gt;Design patterns&lt;/h2&gt;

&lt;p&gt;The ability to dictate color, shape, size and behavior of elements means we can create design patterns that are easy to repeat, and assist the user in interacting with and understanding a design. Our ability to quickly reuse patterns saves us time in the design process. Remember that users are humans â theyâre creatures of habit. Patterns allow users to become easily acclimated to a design. Patterns will also allow users to manufacture habits of interaction and recognition. &lt;/p&gt;

&lt;h2&gt;Consistency&lt;/h2&gt;

&lt;p&gt;Reuse core interactions in a designâs micro experiences. This will build consistency in a design and can increase usersâ engagement and comfort. Where patterns allow for habitual experiences, consistency allows for predictability, smoothness and comfort in experiences. Consistency will not only keep your users happy but will often encourage them to represent your experience to others in a positive light.&lt;/p&gt;

&lt;p&gt;The next time you find your time is limited, play to the advantage of the user by focusing on practices like these that help maintain quality and focus and directly impact your usersâ experiences. Your end result will be more likely to satisfy the goals youâve set within the limited time you have.&lt;/p&gt;
</content>
  </entry><entry>
    <title>An Existential Redesign</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/07/27/an-existential-redesign" />
    <id>https://dockyard.com/blog/2015/07/27/an-existential-redesign</id>
    <category term="design-thinking" label="Design Thinking"/><category term="business" label="Business"/><category term="user-experience" label="User Experience"/><category term="design" label="Design"/><category term="design-process" label="Design Process"/>
    <published>2015-07-27 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>Reflections on the experience of creating the new DockYard</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/m6qxC6g.jpg&quot; alt=&quot;The visual evolution&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; Particularly in branding oriented design, designing for yourself &lt;em&gt;really is&lt;/em&gt; much harder than designing for others. Iteration is important, but ensuring youâre iterating in the direction you actually want to be heading is equally (if not more) important.&lt;/p&gt;

&lt;p&gt;When we started our company repositioning, we knew we had a great, passionate team of designers and engineers together in one office space. We knew that our focus on collaboration would allow us to create something larger than ourselves. The unique story wasnât that we collaborate, but is more about who we are and why weâre here together. What weâve come to realize is that everyone, whether theyâre a designer, developer, or project manager, is here to deliver the most impactful and delightful user experience they can. Period. Full stop.&lt;/p&gt;

&lt;p&gt;Communicating those goals to everyone outside the walls of the business is the real challenge, however. Boiling down those huge goals that are important to us (the reasons we exist) into something that is consumable and effective for the business is a struggle. Most of the writing felt inaccurate, fluffy, or just purely missed the mark. The same was true for visual communication of that language.&lt;/p&gt;

&lt;p&gt;Weâre in the client services industry and that means the messaging is not really about us, our story, or our work. Itâs about how we solve problems for the businesses we serve in a way that is long lasting, thorough, and exceedingly performant. This is what our team is able to do, and this is what matters to both our clients and to us. This is where our objectives clearly align with our clients. This is where we found our focus.&lt;/p&gt;

&lt;p&gt;Iâm very happy with the release of our site and company direction, and I hope youâll benefit from the detail on the challenges and personal growth we experienced in the process.&lt;/p&gt;

&lt;h2&gt;The sawing in the garage&lt;/h2&gt;

&lt;p&gt;It started small, quiet, with hardly any expectation to grow into a project. We were experimenting to see what something more representative of our design process and skill might look like. And what a very big project that became.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/BoA1Q9Z.jpg&quot; alt=&quot;Early sketches in the design process&quot;&gt;&lt;/p&gt;

&lt;p&gt;Initially, we were in unbound exploration mode using our 20% time (we reserve Fridays for improving craft / professional development) to freely experiment with the design vision for DockYard. Undoubtedly a valuable use of time as it stirred up the realization of our need for a full repositioning, but the actual scope of the project crept up on us fast.&lt;/p&gt;

&lt;p&gt;When the project became more serious we did not formalize our process as we would have with any of our client projects. This sucked. We wanted it to be perfect and decided weâd spend whatever time we needed to make it so. But, as many of you know, this can become (and was) the enemy of production. We suffered for it, for a period, but the experimentation did lead to something very good. Once we discovered and felt the pains of not running through our own processes, we ate our own dog food and pushed onward with everything we had learned from the experiments.&lt;/p&gt;

&lt;h2&gt;Sit down, stand up&lt;/h2&gt;

&lt;p&gt;We followed many paths. Many were really not optimal, even though at times quite beautiful. Only a few actually made any business sense.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Illustrate darn near everything&lt;/strong&gt;
This is one of those reactions to your own work where you feel a little crammed in a box and just want to âdo youâ. After a couple days of self reflection on this we had to tell ourselves the obvious: weâre designing a site for a product design and development services company, not a game or event promotional site. This served the latter much better than the former, and we moved on after a few iterations that included degrees of illustration use. While beautiful, unique, and fun to experiment with, they didnât meet our own business goals. It was part of what we do, not &lt;strong&gt;all&lt;/strong&gt; we do.
&lt;img src=&quot;https://i.imgur.com/J9tpLl9.jpg&quot; alt=&quot;Illustrated city over a world of water that contained the rest of the page content&quot;&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Patterns&lt;/strong&gt;
Some pattern work was considered for masthead imagery, but ultimately it never communicated anything, so we killed that as well. Perhaps weâll bring back some patterns in the future, but itâs going to depend on the content of the page. In these cases they felt like mere decoration without reason.
&lt;img src=&quot;https://i.imgur.com/SaCLphO.jpg&quot; alt=&quot;An animated grid pattern concept&quot;&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Photography&lt;/strong&gt;
â¨We relied upon photography pretty heavily for our last site, and perhaps subconsciously we decided we would avoid it for the new site. Because we did, and for a long time. We used some silly photographs here and there that we found as placeholder, but didnât take the approach seriously until iteration began on the site design you see today.
&lt;img src=&quot;https://i.imgur.com/y0eZm7r.jpg&quot; alt=&quot;A very silly placeholder photography of an astronaut on fire&quot;&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Content is hard, people!&lt;/h2&gt;

&lt;p&gt;We knew it wasnât going to be easy, of course, but then we tried hiring an outside editor to help us improve the content we had created according to our messaging goals. They made a lot of promises, and we framed our project timeline around them. After several disappearances and  excuses, then later finding out that they never made movement on the work, we moved on. We went back to the process we use for every blog post: one owner of the content, and team review on Github or Google Docs.&lt;/p&gt;

&lt;p&gt;Aside from that, we had created a lot of content over the years, but had deemed it all out of date with our current thinking. So we wrote it all over again. In the process of writing we discovered better branding positioning and a better content strategy.&lt;/p&gt;

&lt;h2&gt;Continuous integration&lt;/h2&gt;

&lt;p&gt;Embracing the concept of iteration on a marketing site is actually pretty strange in practice. Iâm very used to the experience within application product design and development, but much less so with a site that is supposed to communicate a well formed brand message and is typically considered very static.&lt;/p&gt;

&lt;p&gt;But that message will never be perfect, will it? Putting up a site like ours and planning on iterating on the messaging feels a bit like sending an extremely important e-mail before you had a chance to read over what you had just written. But our site really isnât that one-and-done static marketing site anymore: itâs to constantly evolve with us and our thinking.&lt;/p&gt;

&lt;p&gt;We treat our releases now like we would any client project. We experiment, collaborate, create timelines, do reviews, and dedicate people to the project full time. This is how weâre able to deliver on client projects, and itâs how weâll continue to deliver on the DockYard website, events, and other projects.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/PtDC6HB.gif&quot; alt=&quot;An evolution of our logomark&quot;&gt;&lt;/p&gt;

&lt;p&gt;The site and brand are a significant improvement over what weâve had in the past, and theyâre a great base for continuous iteration. Content, photography, illustration, and even branding will evolve with much greater ease here, and that makes me very excited for whatâs to come.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Using bare arguments with Ember components</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/07/24/using-bare-arguments-with-ember-components" />
    <id>https://dockyard.com/blog/2015/07/24/using-bare-arguments-with-ember-components</id>
    <category term="ember" label="Ember.js"/>
    <published>2015-07-24 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Dan McClain</name></author>
    <summary>Positional parameters help you create cleaner APIs for your components</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/dockyard/ember-cli-async-button&quot;&gt;&lt;code&gt;ember-cli-async-button&lt;/code&gt;&lt;/a&gt;
provides you with a button that changes state
based on a promise in an action. We received a request a while back to allow
users to pass parameters to the action the &lt;code&gt;async-button&lt;/code&gt; calls. We provided
the following API for doing so:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{async-button model action=&amp;quot;save&amp;quot; default=&amp;quot;Save&amp;quot; pending=&amp;quot;Saving...&amp;quot;}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;async-button&lt;/code&gt; calls the following &lt;code&gt;save&lt;/code&gt; action:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    save(callback, model) {
      callback(model.save());
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice that the callback function is still your first argument, but you get the
model as the second argument now. Prior to Ember 1.13, you had to create a
helper which looked through the parameters passed in, and instantiate the
component, and pass the parameters down. And you had to worry about bindings
and streams, so this was a bit complicated.&lt;/p&gt;

&lt;h2&gt;Positional Parameters&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://emberjs.com/blog/2015/06/12/ember-1-13-0-released.html&quot;&gt;With the release of Ember
1.13&lt;/a&gt;,
components have a special property called &lt;code&gt;positionalParams&lt;/code&gt;, which can be an
array of strings that would translate parameters in the component instantiation
into properties on the component.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{x-foo &amp;quot;Dan&amp;quot; &amp;quot;McClain&amp;quot;}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// x-foo component&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;positionalParams&lt;/span&gt;: [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;]
});

&lt;span class=&quot;comment&quot;&gt;// Retrieving the values&lt;/span&gt;
Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &amp;quot;Dan&amp;quot;&lt;/span&gt;
Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);  &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &amp;quot;McClain&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;&amp;quot;Dan&amp;quot;&lt;/code&gt; and &lt;code&gt;&amp;quot;McClain&amp;quot;&lt;/code&gt; would be set as &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;,
respectively, on the component. You may ask &amp;quot;What if we want to have an
arbitrary number of parameters passed to our component?&amp;quot; Well, that&amp;#39;s handled
for you too! If &lt;code&gt;positionalParams&lt;/code&gt; is a string, instead of an array, the
parameters passed to your component will be an array set to that property.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{x-foo &amp;quot;Dan&amp;quot; &amp;quot;McClain&amp;quot;}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// x-foo component&lt;/span&gt;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;positionalParams&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;nameParts&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

&lt;span class=&quot;comment&quot;&gt;// Retrieving the values&lt;/span&gt;
Ember.get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;nameParts&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [&amp;quot;Dan&amp;quot;, &amp;quot;McClain&amp;quot;]&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Cleaning up &lt;code&gt;ember-cli-async-button&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;We no longer have to make a helper to clean up our API for &lt;code&gt;async-button&lt;/code&gt;, and
&lt;a href=&quot;https://github.com/dockyard/ember-cli-async-button/commit/79ce87f01e3244f0e0fa8aff9b4e76f18a5eeed8&quot;&gt;here is the commit where I did
so&lt;/a&gt;.
&lt;a href=&quot;https://github.com/dockyard/ember-cli-async-button/commit/79ce87f01e3244f0e0fa8aff9b4e76f18a5eeed8#diff-d6ef0b16dc1a1a16373acd916a9f56f8R9&quot;&gt;I set the &lt;code&gt;positionalParams&lt;/code&gt;
here&lt;/a&gt;.
&lt;a href=&quot;https://github.com/dockyard/ember-cli-async-button/commit/79ce87f01e3244f0e0fa8aff9b4e76f18a5eeed8#diff-e5b0699b77066e62a7221d9735d743c4L1&quot;&gt;Note that I removed the helper that we had previously used to provide the same
API&lt;/a&gt;.
When you are creating a component and you want a way to pass parameters
that are not explicitly bound to properties, you can now use
&lt;code&gt;positionalParams&lt;/code&gt;, and not muck around with helpers and streams just to pass
info into your component!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Color and culture</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/07/15/color-and-culture" />
    <id>https://dockyard.com/blog/2015/07/15/color-and-culture</id>
    <category term="design" label="Design"/><category term="user-experience" label="User Experience"/><category term="ux-design" label="Ux Design"/><category term="color" label="Color"/><category term="art" label="Art"/>
    <published>2015-07-15 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Part 2 of 4 in the UX color series</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;This post is based on a talk I will be presenting at &lt;a href=&quot;http://uxcamp.com/&quot;&gt;UX Camp&lt;/a&gt; July 18â20, 2015.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Four posts in this series:
- &lt;a href=&quot;https://dockyard.com/blog/2015/06/25/color-1-art-history&quot;&gt;Part 1: Color use in art history&lt;/a&gt;
- &lt;strong&gt;Part 2: Color in culture - understand your own assumptions&lt;/strong&gt; &lt;em&gt;(youâre reading it!)&lt;/em&gt;
- &lt;em&gt;Part 3: A quick intro to color theory (coming soon)&lt;/em&gt;
- &lt;em&gt;Part 4: A three-step approach to selecting color for UX design (coming soon)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;A dangerous color combination&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/MTiklTJ.jpg&quot; alt=&quot;yellow and blue painted fence&quot;&gt;&lt;/p&gt;

&lt;p&gt;This was a fence painted blue and yellow. It stood around a kindergarten building in Moscow, Russia early last year. The color of the fence almost caused the kindergarten to be shut down. Because, at about the same time, there was political turmoil between Russia and Ukraine and the fence colors just happened to be a cheery combination of blue and yellow that matched the Ukrainian flag.&lt;/p&gt;

&lt;p&gt;After the brief scare, the kindergarten was not shut down or burned to the ground. Instead, they simply had to repaint the fence.&lt;/p&gt;

&lt;p&gt;This shows we canât use colors without understanding their cultural context. Letâs look at some other curious examples of what colors could mean to audiences of differing cultures.&lt;/p&gt;

&lt;h2&gt;Did Ancient Greeks care about color?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/FyimJwL.jpg&quot; alt=&quot;Dark maroon sea photo&quot;&gt;
&lt;a href=&quot;https://www.flickr.com/photos/xeubix/2544387679/in/photostream/&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are &lt;a href=&quot;http://www.nytimes.com/1983/12/20/science/homer-s-sea-wine-dark.html&quot;&gt;dozens of references&lt;/a&gt; to a âwine-dark seaâ in the Iliad and the Odyssey. But did Homer actually mean that the sea was the same, deep red, color as wine?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Eg5k2Kp.jpg&quot; alt=&quot;Primary colors arranged from light yellow to dark blue with red in the middle&quot;&gt;&lt;/p&gt;

&lt;p&gt;Not necessarily. It is still a mystery to historians how exactly color was perceived in ancient Greece. My favorite explanation is that color, meaning hue, did not matter as much as how dark or light an object appeared.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/ciUZFQG.jpg&quot; alt=&quot;Umberto Eco color diagram&quot;&gt;&lt;/p&gt;

&lt;p&gt;Color systems in Greek, Latin and other languages do not map neatly to the rainbow. Umberto Eco compares the &lt;a href=&quot;https://books.google.com/books?id=DRd1DZ-5MX0C&amp;amp;lpg=PA168&amp;amp;dq=color%20umberto%20eco%20Hanunoo&amp;amp;pg=PA170#v=onepage&amp;amp;q&amp;amp;f=false&quot;&gt;color terms in the HanunÃ³&amp;#39;o language&lt;/a&gt; to the ones we use today. Instead of hue, tint and shade, they describe objects as light and dark, but also fresh vs. dry and edible vs. inedible.&lt;/p&gt;

&lt;h2&gt;Color is poetry&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/JGdn7kd.jpg&quot; alt=&quot;Japanese kimono with layers of colored silk on a print&quot;&gt;&lt;/p&gt;

&lt;p&gt;Japan in the Heian period is the opposite of Homerâs Greece. People at court really care about colors. By looking at the arrangement of the layers of silk in someoneâs sleeve, you could judge their social status, sophistication, and knowledge of the arts.&lt;/p&gt;

&lt;h2&gt;How do you read a color?&lt;/h2&gt;

&lt;h3&gt;Green&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/PaS1pum.jpg&quot; alt=&quot;Islam, recycling, yes symbols collage&quot;&gt;&lt;/p&gt;

&lt;p&gt;The color green is most often used to mean money. It just happens that one of the richest countries in the world prints âgreenbacksâ. Our green currency is partially due to the plentiful and stable ink that was available at the time, but also related to an earlier Dutch reference: the cloth on bankersâ money counting tables used to be a deep emerald green. Regardless of the source - other countries with much more varied color currencies simply had to adjust to how the US reads âgreenâ.&lt;/p&gt;

&lt;p&gt;In predominantly Muslim countries, a stronger cultural reference for the color green is the religion of Islam.&lt;/p&gt;

&lt;p&gt;When  weâre talking about natural things, or, say, sourcing construction materials - green stands for ecology and recycling.&lt;/p&gt;

&lt;p&gt;And, of course, the meaning of green in user interfaces is similar to a traffic light: green is âsuccessâ.&lt;/p&gt;

&lt;p&gt;Letâs keep going.&lt;/p&gt;

&lt;h3&gt;Blue&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/FPsiodw.jpg&quot; alt=&quot;Mary and Krishna and accessible and hyperlink collage&quot;&gt;&lt;/p&gt;

&lt;p&gt;The same blue can refer symbolically to Maryâs clothing (the âreservedâ color of Ultramarine blue), or the skin of Krishna, and in modern days - to accessibility or web links.&lt;/p&gt;

&lt;h3&gt;Red&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Jdpj3uv.jpg&quot; alt=&quot;Communism and traditional bride and stop sign&quot;&gt;&lt;/p&gt;

&lt;p&gt;Red is used consistently in traditional bridal-wear, in combination with gold. Politically, red often refers to Communism. In interfaces, the most common use of red is to show an error or a warning (like a stop sign) but I find that in Chinese interfaces, red has much less connection to âerrorâ and is used more freely as an additional brand color.&lt;/p&gt;

&lt;h3&gt;Yellow&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Ib8Gxgp.jpg&quot; alt=&quot;buddhist monks and alert message and school sign&quot;&gt;&lt;/p&gt;

&lt;p&gt;Just a few examples of âobviousâ meanings of yellow: Buddhist monks, alert messages, a school bus, and sunshine.&lt;/p&gt;

&lt;h2&gt;Itâs a mess. Where do we go from here?&lt;/h2&gt;

&lt;p&gt;So weâve seen examples of color meaning that contradict each other (which one to pick?) There are many more. We took time to look at them so that we can be sufficiently scared of misunderstanding our users. This way, weâll actually do our research.&lt;/p&gt;

&lt;p&gt;The formula is this: add together politics, cultural context, language differences, and how important color is to the audience. This is how you know where to check for mistakes in selecting UI and brand colors. Always check your defaults and assumptions, and youâll reduce the risk of a cultural #facepalm.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Changing your environment will change your work</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/07/13/changing-your-environment-post" />
    <id>https://dockyard.com/blog/2015/07/13/changing-your-environment-post</id>
    <category term="ux-camp" label="Ux Camp"/><category term="design" label="Design"/><category term="creativity" label="Creativity"/>
    <published>2015-07-13 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Look at expectations, people, and surroundings to help you accomplish that dream project</summary>
    <content type="html">&lt;h2&gt;Environment is key to the way we learn and work&lt;/h2&gt;

&lt;p&gt;We often hear stories of genius artists and designers working hard and defying their odds. And while this is certainly an option, I want to talk about the opposite: we have the power to intentionally move into an environment that supports our creative process.&lt;/p&gt;

&lt;p&gt;We often think of âenvironmentâ as a physical space, but people and expectations can determine our mental work space regardless of physical location.&lt;/p&gt;

&lt;h2&gt;1. Physical location&lt;/h2&gt;

&lt;p&gt;It seems obvious, but the physical location â the room, the set-up, the potential distractions and the familiarity of the space â play an important role. Many creatives choose to work in coffee shops, hotels or other âanonymousâ spaces because leaving their home office helps focus on the task at hand. It can be easier to focus against an unfamiliar environment, rather than to focus against an intimately familiar space of your own house â full of potentially distracting things you could do.&lt;/p&gt;

&lt;p&gt;In addition to focus, we can gain inspiration and a fresh perspective from traveling to a new place. These will reflect in the content, as well as the quality of work.&lt;/p&gt;

&lt;h2&gt;2. Momentum&lt;/h2&gt;

&lt;p&gt;Studies show that &lt;a href=&quot;https://books.google.com/books?id=RsMNiobZojIC&amp;amp;lpg=PA291&amp;amp;ots=FGHqyv4MMT&amp;amp;dq=people%20eat%20more%20in%20groups%20than%20alone%20study&amp;amp;pg=PA291#v=onepage&amp;amp;q&amp;amp;f=false&quot;&gt;people eat more when they have the momentum of eating in a group&lt;/a&gt;. For work, too, the momentum of a group doing a similar thing at once can be powerful. Imagine trying to study in a loud dorm room, or focusing on a project while everyone else in your house is doing the normal weekend activities: preparing for a barbecue, watching a favorite TV show or just socializing. Normally, we try to improve our working conditions simply by removing the distractions: getting a quiet place to concentrate, where no TV show is competing for our attention. &lt;/p&gt;

&lt;p&gt;Why not go a step farther? Purposefully placing yourself into an environment where the momentum points toward producing creative work tips the balance in your favor.&lt;/p&gt;

&lt;h2&gt;3. Expectations&lt;/h2&gt;

&lt;p&gt;And while weâre on the subject of momentum â just being in an environment where people expect that youâve showed up to do creative work can support your process. Normally, the first step is to start â to make the decision to work on a creative project right here and right now. In a dedicated time and space, when you have intentionally decided to set aside a weekend for creative work, and made the effort to show up, you are now removing the choice of whether to start on that project or not. The expectations of everyone around you will nudge you forward.&lt;/p&gt;

&lt;p&gt;This is true for many types of environments: dedicated âproject workâ time in a college class, an art studio where you might attend life drawing sessions, a co-working office space, or even a very supportive office environment when creative projects are encouraged on set-aside time. However, we stumble across fewer and fewer of these environments as our careers progress (whenâs the last time you took a college class?), so it is important to purposefully place ourselves in them.&lt;/p&gt;

&lt;h2&gt;4. Feedback&lt;/h2&gt;

&lt;p&gt;Another important aspect of a working environment is giving and receiving feedback. It can help you when you feel stuck on a project, but more importantly, it can help you realize things you have not seen from your perspective. Basically, find out that you were stuck without even knowing it.&lt;/p&gt;

&lt;p&gt;Creative feedback is a two-way process: in order to receive it, we have to be prepared to give it as well. Investing time to learn about othersâ process and goals may feel like a setback when you are eager to make progress on your own ideas, but, aside from being a fair exchange, itâs also beneficial to broaden your frame of reference.&lt;/p&gt;

&lt;p&gt;Giving and receiving feedback openly has another advantage. When you expect to share your work in a supportive environment, youâre mentally preparing to explain your project to someone who is unfamiliar with it. Just the effort of translating your thoughts into a clear outline for others to understand can expose potential improvements in the process, and make your work better before you even begin to share it. In a common scenario, you could start explaining a complex bug youâve been dealing with, then stop halfway with an âaha!â because the explanation caused you to solve the problem yourself.&lt;/p&gt;

&lt;h2&gt;5. The nudge&lt;/h2&gt;

&lt;p&gt;Sharing your work, even with a small group of like-minded creative people, can also nudge you to wrap up any loose pieces and present it well. It is often easier to complete some portion of a project, even in draft form, instead of explaining over and over again what you imagine that component to be in the future. &lt;/p&gt;

&lt;p&gt;I had this ânudgeâ happen to me recently, as I was presenting a short talk here at DockYard about an idea I had been working on. I mentioned the domain name I had registered for it, but at the time of the talk, the website was still in draft mode. Brian called me out on that â âthereâs nothing there yet!â â and I quickly proceeded to publish the site to be able to support my words when I mention the project again.&lt;/p&gt;

&lt;h2&gt;In summary&lt;/h2&gt;

&lt;p&gt;As we prepare for &lt;a href=&quot;http://uxcamp.com/&quot;&gt;UX Camp&lt;/a&gt;, I realize more and more that the environment we are building is special exactly because it embodies all of the qualities of a supportive working environment. And the type of people who will go out of their way to rural Maine for a project-based learning weekend are exactly the type of people I want to be around.&lt;/p&gt;
</content>
  </entry><entry>
    <title>My project for UX Camp summer 2015</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/07/08/my-project-for-ux-camp-2015" />
    <id>https://dockyard.com/blog/2015/07/08/my-project-for-ux-camp-2015</id>
    <category term="ux-east" label="Ux East"/><category term="ux-camp" label="Ux Camp"/><category term="repeat-pattern" label="Repeat Pattern"/><category term="pattern" label="Pattern"/><category term="design" label="Design"/>
    <published>2015-07-08 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>I&#39;m making repeat patterns. How about you?</summary>
    <content type="html">&lt;p&gt;Iâm super excited to attend (and help organize) this summerâs &lt;a href=&quot;http://uxeast.org/&quot;&gt;UX Camp&lt;/a&gt;. Last fall we had an inspiring, productive weekend and this year I expect even more.&lt;/p&gt;

&lt;p&gt;The camp is a project based weekend, meaning that in addition to talks and workshops, we can all bring a project we want to focus on. Today, I want to share what I tried last fall, how it turned out, and what Iâm bringing with me this year.&lt;/p&gt;

&lt;h2&gt;What I got last year&lt;/h2&gt;

&lt;p&gt;Last year, I focused on improving my visual thought process through quick sketching. I brought a clipboard, a felt tip marker and a stack of paper, and practiced quickly and roughly sketching out any ideas or notes that I wanted to capture throughout the event. My set-up (clipboard, paper and one pen) was intentionally minimal because I wanted to be able to pick up the project in the breaks between helping run and document the event, and listening to lectures and workshops.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/K9TBWR9.jpg&quot; alt=&quot;My clipboard from UX Camp last year&quot;&gt;&lt;/p&gt;

&lt;p&gt;The result was encouraging: I was able to fill about 25 sheets with rough drawings, and got a bit more comfortable capturing my ideas in drawing form, rather than as a list or a paragraph of text.&lt;/p&gt;

&lt;h2&gt;What Iâm doing this year&lt;/h2&gt;

&lt;p&gt;This year, I am hoping to try a slightly more involved project: repeat patterns. It will require a few extra tools, and a bit more space than last yearâs.&lt;/p&gt;

&lt;h3&gt;The inspiration&lt;/h3&gt;

&lt;p&gt;I was inspired by Matisse - his paintings and even more, his creative process. He sourced colors and textures for his work from an extensive collection of textiles, artifacts and clothing. I want to create repeat patterns for use online (&lt;a href=&quot;https://dockyard.com/blog/2014/07/23/repeat-patterns&quot;&gt;an existing interest of mine&lt;/a&gt;) by sourcing color and texture inspiration from Matisse.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/PyK5h0F.jpg&quot; alt=&quot;Matisse and his patterns&quot;&gt;&lt;/p&gt;

&lt;h3&gt;The tools&lt;/h3&gt;

&lt;p&gt;To sketch the patterns, I will bring:
- Markers in a few colors
- Sheer marker paper
- Masking tape (to display my results on a window)
- A ruler and a pencil
- Scissors and clear tape to re-combine shapes&lt;/p&gt;

&lt;h3&gt;The process&lt;/h3&gt;

&lt;p&gt;I plan to start with a grid and play with layering patterns on sheer paper to arrive at different solutions. The initial drawings will likely be very messy, but I  expect that the clarity will improve as I work on the same idea a few times.&lt;/p&gt;

&lt;h3&gt;The goal&lt;/h3&gt;

&lt;p&gt;I plan to iterate in public so I can take advantage of the camp setting. While a specific result (pattern) may look good and useful to me, others may offer an unexpected opinion. By showing my work early and getting feedback - even if feedback is anecdotal, like - â&lt;em&gt;yeah, I might use something like that for a web project&lt;/em&gt;â - I will have the advantage of many peopleâs perspectives.&lt;/p&gt;

&lt;p&gt;So, here! Iâve shared my plans for camp! My colleagues at DockYard are getting ready as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tim&lt;/strong&gt; is planning to either focus on a typeface heâs been crafting this year, or begin conceptualizing an idea for a live music website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steve&lt;/strong&gt; is still undecided about what heâll focus on in addition to running the camp. (Perhaps, you can &lt;a href=&quot;https://twitter.com/uxeast&quot;&gt;tweet an idea for him&lt;/a&gt; to work on!)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Patrick&lt;/strong&gt; might finally tackle an infographic heâs been planning to make for &lt;a href=&quot;http://bumpinpumpkinbeer.com/&quot;&gt;a pumpkin beer review site&lt;/a&gt; he runs, so that he can release it in the fall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amanda&lt;/strong&gt; will be working on a future conference talk and learning about animating SVGs.&lt;/p&gt;

&lt;p&gt;What are you excited to work on? &lt;a href=&quot;https://twitter.com/uxeast&quot;&gt;Share your ideas&lt;/a&gt; with us!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Use of color through art history</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/06/25/color-1-art-history" />
    <id>https://dockyard.com/blog/2015/06/25/color-1-art-history</id>
    <category term="design" label="Design"/><category term="user-experience" label="User Experience"/><category term="art" label="Art"/><category term="color" label="Color"/><category term="ux-design" label="Ux Design"/>
    <published>2015-06-25 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Part 1 of 4 in the UX color series</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;This post is based on a talk I presented at &lt;a href=&quot;http://uxburlington.com/&quot;&gt;UX Burlington&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Color is one of the basic tools for UX design. It is very powerful: it affects us psychologically, physiologically, and, of course, aesthetically. But color selection can be intimidating: with millions of options, designers often feel lost because all the options look equally valid.&lt;/p&gt;

&lt;p&gt;In this series, I will show where color is complex, and then suggest a stepâby-step process to make color selection less intimidating.&lt;/p&gt;

&lt;h2&gt;Color was not always a thing.&lt;/h2&gt;

&lt;p&gt;Peopleâs understanding of what color &lt;em&gt;is&lt;/em&gt; has changed over time. Today, we think of it as a continuous spectrum, consisting of millions of options.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/C6BX139.jpg&quot; alt=&quot;Photoshop gradient color picker&quot;&gt;&lt;/p&gt;

&lt;p&gt;Our ability to digitally manipulate color contributes to our understanding of it as an infinite space of millions of options.&lt;/p&gt;

&lt;h2&gt;Medieval color: paint-by-number&lt;/h2&gt;

&lt;p&gt;This was not alway the case. In Medieval Europe, people thought of color as &lt;em&gt;colors&lt;/em&gt; â separate pigments that are made of different physical materials. Where we might think of two blues as related shades of a single color, medieval artists considered Ultramarine blue and Indigo two separate colors, and never mixed these pigments. In fact, ultramarine - a rare imported pigment - was more expensive than gold. Because of this, colors were rarely mixed (giving a distinct âpaint by numberâ look to illuminated manuscripts) and the expensive pigments were reserved to paint nobility, royalty or holy figures.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/ZYTgqHn.jpg&quot; alt=&quot;Medieval art can look like paint-by-number&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Vermeerâs color: under contract&lt;/h2&gt;

&lt;p&gt;In the 1600s, we start seeing the use of color loosen up a bit. Pigments are no longer reserved for specific use. In this example, the milkmaid by Vermeer, is not royalty. But her dress has the precious ultramarine - and it is mixed and glazed over other color to produce a color effect we would call realistic today. However, the pigment was still very expensive, and the amount of ultramarine to be used in the painting was specified precisely in a contract.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/dqFFYj7.jpg&quot; alt=&quot;The Milk Maid by Vermeer&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Industrial revolution: OMG COLORS!&lt;/h2&gt;

&lt;p&gt;The Industrial revolution brought two important innovations to art: synthetic pigments and tube paints. Synthetic pigments started making vibrant colors more available and affordable for artists, and tubes made paint portable for the first time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/UWmb9pz.jpg&quot; alt=&quot;William Perkinâs synthetic mauve color&quot;&gt;&lt;/p&gt;

&lt;p&gt;William Perkinâs Mauve was the first synthetic pigment. It allowed a vibrant shade of purple-fuchsia to be applied in a stable manner to fabric and of course to paint. Other pigments followed, and soon there was enough to make art a bit too colorful for some tastes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/I1VUkov.jpg&quot; alt=&quot;All colorful art in a single graph&quot;&gt;&lt;/p&gt;

&lt;p&gt;The invention of paint tubes by Windsor and Newton allowed artists to bring painting outside. So, where before we saw the sky, the trees and the hay their respective âproperâ colors, modulated by dark shadows and bright highlights, impressionists started painting from observation and added all kinds of wild atmospheric colors to their hay.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/ET5v2Zz.jpg&quot; alt=&quot;The HayStacks&quot;&gt;&lt;/p&gt;

&lt;p&gt;After impressionism came expressionism. Here, Van Gogh does not show his impression of the way the room looked by using these vibrant, almost âacidicâ colors. Instead, he expresses his emotions through how he treats the appearance of the room. By this time, the use of color moves away from realism and towards expressing artistic goals.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/FIFalds.jpg&quot; alt=&quot;The Red Room - Van Gogh&quot;&gt;&lt;/p&gt;

&lt;h2&gt;1950s: color is the message&lt;/h2&gt;

&lt;p&gt;Even farther from references to reality - this 1950s piece by Yves Klein uses color by itself as the message. In fact, the artist patented the chemical process to make this pigment (very similar to a synthetic ultramarine) and made the pigment itself a central part of his artwork for the remainder of his career.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/bGYDuTJ.jpg&quot; alt=&quot;IK Blue as a monumental art piece&quot;&gt;&lt;/p&gt;

&lt;h2&gt;1960s: any color you want!&lt;/h2&gt;

&lt;p&gt;By the time we get to pop art, the technology behind making pigments has become so advanced that we as consumers became used to expecting any mass produced product to be able to be any color we want. This is why, in pop art, we see the color variations of Warholâs Marilyn and they seem equally valid. Any color selection, as long as it is intentional, can be as good as any other.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/Jd5v3Le.jpg&quot; alt=&quot;Warholâs Marilyn prints&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Where are we now?&lt;/h2&gt;

&lt;p&gt;In summary - we went from color being an inseparable, intrinsic part of the material something is made of, to color being a changeable, almost arbitrary attribute of a thing. With seemingly all the possible (digital) colors at our fingertips, it is no wonder we are lost for choice. It is understandable to feel a overwhelmed by the selection.&lt;/p&gt;

&lt;p&gt;In the next post, I will explore the meaning different cultures can give to color.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Copy to Clipboard Without Using Flash!</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/06/19/copy-to-clipboard-without-using-flash" />
    <id>https://dockyard.com/blog/2015/06/19/copy-to-clipboard-without-using-flash</id>
    <category term="javascript" label="JavaScript"/>
    <published>2015-06-19 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Marin Abernethy</name></author>
    <summary>&quot;document.execCommand()&quot; has now added support for &quot;copy&quot; in some browsers</summary>
    <content type="html">&lt;p&gt;For a long time we&amp;#39;ve had to rely on Flash plugins like &lt;a href=&quot;https://github.com/zeroclipboard/zeroclipboard&quot;&gt;ZeroClipboard&lt;/a&gt; 
to copy text to the clipboard. While Flash still remains the only cross-browser solution for copying to a userâs clipboard, 
some browsers have recently added the ability to trigger &lt;code&gt;cut&lt;/code&gt; and &lt;code&gt;copy&lt;/code&gt; using &lt;code&gt;document.execCommand()&lt;/code&gt;! Specifically, 
&lt;a href=&quot;http://caniuse.com/#search=clipboard%20API&quot;&gt;IE10+, Chrome 43+, and Opera29+&lt;/a&gt;. Firefox seems to have some
&lt;a href=&quot;http://kb.mozillazine.org/Granting_JavaScript_access_to_the_clipboard&quot;&gt;options&lt;/a&gt; that allow users to grant permissions 
to certain sites to access the clipboard, but I haven&amp;#39;t tried it out myself.&lt;/p&gt;

&lt;p&gt;For those of you not familiar with &lt;code&gt;execCommand()&lt;/code&gt;, it is  more than just &lt;code&gt;cut&lt;/code&gt; and &lt;code&gt;copy&lt;/code&gt;! It is one of the core methods
of rich-text editing in browsers. You can manipulate the contents of the current document, current selection, or a 
specified range through various commands. Some other common commands include: &lt;code&gt;bold&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;,  &lt;code&gt;createLink&lt;/code&gt;, and 
&lt;code&gt;indent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;execCommand(commandName [, showUI [, value]])&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;commandName&lt;/code&gt; (String): the property that you are validating.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;showUI&lt;/code&gt; (Boolean) &lt;em&gt;optional&lt;/em&gt;: Display a user interface if the command supports one. Defaults to false.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt; (DOMString) &lt;em&gt;optional&lt;/em&gt;: Specifies the string, number, or other value to assign. Possible values
depend on the command. Pass an argument of null if no argument is needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You must set &lt;code&gt;document.designMode = &amp;quot;on&amp;quot;&lt;/code&gt;, or set &lt;code&gt;contenteditable=&amp;quot;true&amp;quot;&lt;/code&gt; on the element that you wish to use &lt;code&gt;execCommand()&lt;/code&gt; on. &lt;/p&gt;

&lt;p&gt;However, like &lt;code&gt;cut&lt;/code&gt; and &lt;code&gt;copy&lt;/code&gt;, not all commands are enabled across all browsers. I created 
an &lt;a href=&quot;http://emberjs.jsbin.com/hagupu/5/edit?html,js,output&quot;&gt;Ember JSBin&lt;/a&gt; with a simple WYSIWYG
to demonstrate some of what &lt;code&gt;execCommand()&lt;/code&gt; can do. Feel free to play around! &lt;/p&gt;

&lt;p&gt;Now to demonstrate how &lt;code&gt;execCommand&lt;/code&gt; paired with the Selection API can easily copy to a user&amp;#39;s clipboard. 
Below is our HTMLBars with a promo code string that we want to copy.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;p&amp;gt;Promo code: &amp;lt;span class=&amp;quot;promo-code&amp;quot;&amp;gt;SALE123&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;button {{action &amp;quot;copyToClip&amp;quot;}}&amp;gt;Copy&amp;lt;/button&amp;gt;&amp;lt;/p&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When the &lt;code&gt;Copy&lt;/code&gt; button is clicked, the following action will be called:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;function&quot;&gt;copyToClip&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  const promoCode = document.querySelector(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.promo-code&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const range = document.createRange();  
  range.selectNode(promoCode);  
  window.getSelection().addRange(range);
  document.execCommand(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); 
  window.getSelection().removeAllRanges();
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this action we create a range of the document and add our promo code text as a node of that range. We then 
use the Selection API method &lt;code&gt;window.getSelection().addRange()&lt;/code&gt; to add the part of the document we want to copy
to the user&amp;#39;s &lt;code&gt;selection&lt;/code&gt;. &lt;code&gt;document.execCommand(&amp;#39;copy&amp;#39;)&lt;/code&gt; then copies that selection to the clipboard. 
And finally, we remove the selection by calling &lt;code&gt;window.getSelection().removeAllRanges()&lt;/code&gt; so that the user 
never sees the highlighting.&lt;/p&gt;

&lt;p&gt;And that&amp;#39;s it! If you wanted to confirm everything worked as expected you can examine the response of 
&lt;code&gt;document.execCommand()&lt;/code&gt;; it returns &lt;code&gt;false&lt;/code&gt; if the command is not supported or enabled.&lt;/p&gt;

&lt;p&gt;You can check this example out in this &lt;a href=&quot;http://emberjs.jsbin.com/faqixa/3/edit?html,js,output&quot;&gt;Ember JSBin&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Maintaining a session in Phoenix integration tests</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/06/12/maintaining-session-in-phoenix-integration-tests" />
    <id>https://dockyard.com/blog/2015/06/12/maintaining-session-in-phoenix-integration-tests</id>
    <category term="phoenix" label="Phoenix"/><category term="testing" label="Testing"/><category term="elixir" label="Elixir"/>
    <published>2015-06-12 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Dan McClain</name></author>
    <summary>Your server has authentication, and you want to be authenticated in your tests</summary>
    <content type="html">&lt;p&gt;I&amp;#39;m using &lt;a href=&quot;http://www.phoenixframework.org&quot;&gt;Phoenix&lt;/a&gt; to power the backends for a couple of Ember projects I am
writing. For those applications, I&amp;#39;ve been using OAuth2 + cookie-based sessions
to authenticate my users. When testing the authentication flow, I wanted
to make sure that I was properly retrieving my session from the cookie I
previously set.&lt;/p&gt;

&lt;h2&gt;The hard way (pre Phoenix v0.13)&lt;/h2&gt;

&lt;p&gt;The following maintains a session across multiple requests:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;test &amp;quot;Creating a session with a GitHub code&amp;quot; do
  use_cassette &amp;quot;successful_sign_in&amp;quot; do
    response = conn(:post, &amp;quot;/api/v1/session&amp;quot;, %{ &amp;quot;authorizationCode&amp;quot; =&amp;gt; &amp;quot;dan&amp;quot;, &amp;quot;format&amp;quot; =&amp;gt; &amp;quot;json&amp;quot;, &amp;quot;provider&amp;quot; =&amp;gt; &amp;quot;github-oauth2&amp;quot; })
    |&amp;gt; DoorApi.Endpoint.call([])

    assert response.status == 201

    current_session_request = conn(:get,  &amp;quot;/api/v1/session&amp;quot;)

    current_session_response = response.cookies
    |&amp;gt; Enum.reduce(current_session_request, fn ({key, value}, conn) -&amp;gt; put_req_cookie(conn, key, value) end)
    |&amp;gt; DoorApi.Endpoint.call([])

    assert current_session_response.status == 200
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above code copies the cookies from the first (completed) request, and
appends them to the second request. This allows you to retrieve information
from the session returned in the first request.&lt;/p&gt;

&lt;h2&gt;But wait! There is a better way&lt;/h2&gt;

&lt;p&gt;With the release of Phoenix v0.12, new test helpers debuted that allow for the
concept of connection recycling.  TL;DR: the new helpers create a new
connection with the details of the old, completed connection. We can update our
first example to use the new helpers:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;test &amp;quot;Creating a session with a GitHub code&amp;quot; do
  use_cassette &amp;quot;successful_sign_in&amp;quot; do
    # We call the conn function to get us an initial connection.
    # From then on, we just pass the result of the last request to the helpers
    conn = post(conn(), &amp;quot;/api/v1/session&amp;quot;, %{ &amp;quot;authorizationCode&amp;quot; =&amp;gt; &amp;quot;dan&amp;quot;, &amp;quot;format&amp;quot; =&amp;gt; &amp;quot;json&amp;quot;, &amp;quot;provider&amp;quot; =&amp;gt; &amp;quot;github-oauth2&amp;quot; })

    assert conn.status == 201

    conn = get(conn, &amp;quot;/api/v1/session&amp;quot;)

    assert conn.status == 200
  end
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The helpers remove the need to call our endpoint, and make the code much more concise. This is a huge improvement to testing in Phoenix.
&lt;a href=&quot;http://hexdocs.pm/phoenix/Phoenix.ConnTest.html&quot;&gt;You can see a bit more about the helpers in the &lt;code&gt;Phoenix.ConnTest&lt;/code&gt; documentation&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Go: UX Camp 2015</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/06/09/ux-camp-2015" />
    <id>https://dockyard.com/blog/2015/06/09/ux-camp-2015</id>
    <category term="ux-east" label="Ux East"/><category term="design" label="Design"/><category term="design-process" label="Design Process"/><category term="design-thinking" label="Design Thinking"/><category term="conferences" label="Conferences"/><category term="ux-camp" label="Ux Camp"/>
    <published>2015-06-09 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>A weekend away for design collaboration and learning.</summary>
    <content type="html">&lt;p&gt;Letâs go back to camp.&lt;/p&gt;

&lt;p&gt;This July 18-20 weâre heading back up to Maine, and to a really cool (remote) location. We have four cabins on the lake in Caratunk, ME, and I invite you to join us!&lt;/p&gt;

&lt;p&gt;Just like last year, itâs a UX design focused project weekend with intermittent design talks, workshops, games, and music. This year weâre going to have the incredible (Boston based) band &lt;a href=&quot;https://www.youtube.com/watch?v=w6ytkBYaIU4&quot;&gt;The Grownup Noise&lt;/a&gt; performing for us around the camp fire.&lt;/p&gt;

&lt;p&gt;And for those of you who are musicians, I implore you to bring some instruments. There will be musical improvisation, led by The Grownup Noise, and weâd love for you to play along with us.&lt;/p&gt;

&lt;p&gt;If you have questions or are interested in sponsorship, please e-mail me at &lt;a href=&quot;mailTo:steven@dockyard.com&quot;&gt;steven@dockyard.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See you there!&lt;/p&gt;
</content>
  </entry><entry>
    <title>A clean pattern for modal dialogs</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/06/08/a-clean-pattern-for-modal-dialogs" />
    <id>https://dockyard.com/blog/2015/06/08/a-clean-pattern-for-modal-dialogs</id>
    <category term="ember" label="Ember.js"/><category term="components" label="Components"/>
    <published>2015-06-08 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Dan McClain</name></author>
    <summary>The project you are working on has a number of modal dialogs, and the component helper can help</summary>
    <content type="html">&lt;p&gt;Recently, I was working on a project which had a number of different modals. I
discovered a really clean pattern for implementing modals via actions and
&lt;a href=&quot;https://github.com/yapplabs/ember-modal-dialog&quot;&gt;&lt;code&gt;ember-modal-dialog&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We implemented each of the different modals as separate components, and
rendered &lt;code&gt;ember-modal-dialog&lt;/code&gt; in the &lt;code&gt;application&lt;/code&gt; template the following
way:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#if isModalVisible}}
  {{#modal-dialog}}
    {{component modalDialogName modalContext=modalContext closeAction=&amp;quot;closeModal&amp;quot;}}
  {{/modal-dialog}}
{{/if}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The component helper allows us to dynamically choose which modal we&amp;#39;d like to
see. We call the modal via the following action in the application route;&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const { setProperties, set } = Ember;

actions: {
  showModal(modalDialogName, modalContext) {
    const applicationController = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.controller;

    setProperties(applicationController, {
      modalDialogName,
      modalContext,
      &lt;span class=&quot;key&quot;&gt;isModalVisible&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    });
  },

  closeModal() {
    const applicationController = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.controller;

    set(applicationController, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isModalVisible&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;);
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We invoke the modal via a normal action call:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;button {{action &amp;quot;showModal&amp;quot; &amp;quot;my-component-name&amp;quot; contextForModal}}&amp;gt;Show the modal!&amp;lt;/button&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;modalContext&lt;/code&gt; could be as simple as a string, or as complex as an
Ember-Data model. It gets passed to the component as the &lt;code&gt;modalContext&lt;/code&gt;
attribute, so you&amp;#39;ll need to remember to retrieve your properties from within
there if you are trying to do something a bit more complex.&lt;/p&gt;

&lt;p&gt;The component helper is really what enables this pattern, otherwise you&amp;#39;d need
to either have a series of &lt;code&gt;if&lt;/code&gt;s to display the correct modal. I may extract
this pattern into a separate addon, as I see it as one I&amp;#39;ll reuse frequently
whenever we have multiple modal dialogs.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Declarative Breadcrumb Navigation in Ember.js</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/06/02/ember-crumbly" />
    <id>https://dockyard.com/blog/2015/06/02/ember-crumbly</id>
    <category term="javascript" label="JavaScript"/><category term="addon" label="Addon"/><category term="ember" label="Ember.js"/>
    <published>2015-06-02 00:00:00</published>
    <updated>2016-02-01 16:29:40</updated>
    <author><name>Lauren Tan</name></author>
    <summary>ember-crubmly is a simple Component that is placed once in your application, and then generates a dynamic breadcrumb by looking up the current route hierarchy. The addon has a simple declarative API, which makes integration with your app super easy.</summary>
    <content type="html">&lt;p&gt;Breadcrumb navigation isn&amp;#39;t a new concept, in fact, it&amp;#39;s usefulness has been endlessly debated about by UX designers all over. Today, I won&amp;#39;t get into the nitty gritty on whether or not your app should include one, but I&amp;#39;d like to share an addon I built for a project I&amp;#39;m working on that required it.&lt;/p&gt;

&lt;p&gt;This is a simple Component that is placed once in your application, and then generates a dynamic breadcrumb by looking up the current route hierarchy. The addon has a simple declarative API, which makes integration with your app super easy.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s dive in!&lt;/p&gt;

&lt;h2&gt;Demo &amp;amp; Source&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Sutk1UQ.png&quot; alt=&quot;ember-crumbly-demo&quot;&gt;&lt;/p&gt;

&lt;p&gt;You can take a look at the &lt;a href=&quot;http://development.ember-crumbly-demo.divshot.io/&quot;&gt;demo app&lt;/a&gt; to see ember-crumbly in action. What&amp;#39;s cool about it is how little code it takes to add dynamic breadcrumbs to your app, and how declarative it is. The &lt;a href=&quot;https://github.com/poteto/ember-crumbly&quot;&gt;source is on GitHub&lt;/a&gt;, as always.&lt;/p&gt;

&lt;h2&gt;The idea&lt;/h2&gt;

&lt;p&gt;We work on many Ember apps at DockYard, and one particular client&amp;#39;s project I was working on called for a very dynamic breadcrumb type UI that would respond to changes in the route and model. Before I started actually implementing it, I sketched my plan on paper to see if I could make it nice and declarative instead of manually setting the breadcrumb on each of those route templates.&lt;/p&gt;

&lt;h3&gt;The Ember Container and currentRouteName&lt;/h3&gt;

&lt;p&gt;The Component relies mainly on Ember&amp;#39;s container and the current route name. On a high level, the Component is injected with the Application Controller&amp;#39;s &lt;code&gt;currentRouteName&lt;/code&gt; prop, then looks up the appropriate route in the Container to check if it has a &lt;code&gt;breadCrumb&lt;/code&gt; prop defined. If it does, we display whatever the POJO is, or else we show its route name in the Component.&lt;/p&gt;

&lt;h2&gt;Intended usage&lt;/h2&gt;

&lt;p&gt;The goal was to have an API as declarative as the following:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{bread-crumbs linkable=true outputStyle=&amp;quot;foundation&amp;quot;}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And the route:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// foo/route.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  &lt;span class=&quot;key&quot;&gt;breadCrumb&lt;/span&gt;: {
    &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Animals&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We also wanted to be able to pass in our own template block too:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#bread-crumbs linkable=true as |component route|}}
  {{#if route.title}}
    {{route.title}}
  {{else}}
    {{route.foo}} ({{route.bar}}) ... {{route.baz}}
  {{/if}}
{{/bread-crumbs}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s see how we can write a component that does just that using some of Ember&amp;#39;s new features.&lt;/p&gt;

&lt;h2&gt;Injecting the Application Controller&lt;/h2&gt;

&lt;p&gt;I&amp;#39;ve explained how we inject things in other posts, so I won&amp;#39;t go into detail for the initializer. Ember adds the &lt;a href=&quot;http://guides.emberjs.com/v1.10.0/understanding-ember/debugging/#toc_get-current-route-name-path&quot;&gt;currentRouteName and currentPath to the Application Controller&lt;/a&gt;, so we&amp;#39;ll inject it into our Component so we can extract it.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(container, application) {
  application.inject(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;component:bread-crumbs&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;applicationController&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller:application&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
}

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; {
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;crumbly&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  initialize
};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Declaring your variables&lt;/h2&gt;

&lt;p&gt;We typically declare our variables and functions used at the top of each file, to make code easier to read and refactor in the future. For ember-crumbly&amp;#39;s &lt;code&gt;bread-crumbs&lt;/code&gt; component, we&amp;#39;re using the usual suspects:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; layout from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../templates/components/bread-crumbs&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const get = Ember.get;
const {
  &lt;span class=&quot;key&quot;&gt;A&lt;/span&gt;: emberArray,
  EnumerableUtils,
  Component,
  Logger,
  computed,
  getWithDefault,
  assert,
  typeOf,
  setProperties
} = Ember;

const {
  classify
} = Ember.String;

const {
  map,
  filter
} = EnumerableUtils;

const {
  warn
} = Logger;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You might be wondering why we declare &lt;code&gt;const get = Ember.get;&lt;/code&gt; by itself on L4âââcurrently there are issues with destructuring &lt;code&gt;{ get }&lt;/code&gt; and &lt;a href=&quot;https://github.com/dockyard/ember-suave/issues/5&quot;&gt;bugs in Esprima&lt;/a&gt;, so we do it by itself as temporary workaround.&lt;/p&gt;

&lt;h2&gt;Component props&lt;/h2&gt;

&lt;p&gt;Here we set a bunch of default props for the component.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Component.extend({
  layout,
  &lt;span class=&quot;key&quot;&gt;tagName&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ol&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;linkable&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;reverse&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;classNameBindings&lt;/span&gt;: [ &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;breadCrumbClass&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; ],
  &lt;span class=&quot;key&quot;&gt;hasBlock&lt;/span&gt;: computed.bool(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).readOnly(),
  &lt;span class=&quot;key&quot;&gt;currentRouteName&lt;/span&gt;: computed.readOnly(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;applicationController.currentRouteName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We&amp;#39;ve injected the Application Controller into the component in our initializer, so getting the current route&amp;#39;s name is as simple as setting a computed property macro. We make it &lt;a href=&quot;http://emberjs.com/api/classes/Ember.ComputedProperty.html#method_readOnly&quot;&gt;&lt;code&gt;readOnly&lt;/code&gt;&lt;/a&gt; so we don&amp;#39;t set it by accident.&lt;/p&gt;

&lt;h2&gt;Computing the route hierarchy&lt;/h2&gt;

&lt;p&gt;Ember&amp;#39;s &lt;code&gt;currentRouteName&lt;/code&gt; prop returns the current route hierarchy separated by periods. For example, if you were on &lt;code&gt;/foo/bar/baz&lt;/code&gt;, your route would probably be something like &lt;code&gt;foo.bar.baz.index&lt;/code&gt;. Knowing this, the goal would be to split the string by the period, and then working out the route name for each of its parts. With the correct route name, we can then lookup the route on the container and extract the &lt;code&gt;breadCrumb&lt;/code&gt; POJO we need for our bread-crumb.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;routeHierarchy: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;currentRouteName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  get() {
    const currentRouteName = getWithDefault(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;currentRouteName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;);

    assert(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[ember-crumbly] Could not find a curent route&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, currentRouteName);

    const routeNames = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._splitCurrentRouteName(currentRouteName);
    const filteredRouteNames = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._filterIndexRoutes(routeNames);

    const crumbs = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._lookupBreadCrumb(routeNames, filteredRouteNames);
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) ? crumbs.reverse() : crumbs;
  },

  set() {
    warn(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[ember-crumbly] `routeHierarchy` is read only&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You&amp;#39;ll notice straight away that we&amp;#39;re using new Ember computed property syntax here. The new syntax allows you to set both getters and setters on your CP, instead of checking argument length like you used to have to do.&lt;/p&gt;

&lt;h2&gt;Figuring out the route name&lt;/h2&gt;

&lt;p&gt;First, we split the &lt;code&gt;currentRouteName&lt;/code&gt; string into an array, and then filter out any &lt;code&gt;index&lt;/code&gt; routes. This is because the string splits into an array with all the parts, so &lt;code&gt;foo/bar/baz&lt;/code&gt; would yield &lt;code&gt;[ &amp;#39;foo&amp;#39;, &amp;#39;bar&amp;#39;, &amp;#39;baz&amp;#39;, &amp;#39;index&amp;#39; ]&lt;/code&gt;, while we only want the first 3.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_splitCurrentRouteName(currentRouteName) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; currentRouteName.split(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
},

_filterIndexRoutes(routeNames) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; filter(routeNames, (name) =&amp;gt; {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; name !== &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
  });
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now with the array of parts, we need to piece them together again bit by bit to reconstruct their constituent routes.&lt;/p&gt;

&lt;h2&gt;Looking up the route on the container&lt;/h2&gt;

&lt;p&gt;In here, we:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Map over the filtered route names individually&lt;/li&gt;
&lt;li&gt;Reconstruct the route name by slicing the original array of route names with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice&quot;&gt;right &lt;code&gt;end&lt;/code&gt; argument&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Look the reconstructed route name up on the container&lt;/li&gt;
&lt;li&gt;Retrieve the breadCrumb POJO, add props to it, and return an Ember Array that our component can iterate over in its template&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_lookupBreadCrumb(routeNames, filteredRouteNames) {
  const defaultLinkable = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;linkable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const breadCrumbs = map(filteredRouteNames, (name, index) =&amp;gt; {
    const path = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._guessRoutePath(routeNames, name, index);
    let breadCrumb = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._lookupRoute(path).getWithDefault(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;breadCrumb&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;undefined&lt;/span&gt;);
    const breadCrumbType = typeOf(breadCrumb);

    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (breadCrumbType === &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) {
      breadCrumb = {
        path,
        &lt;span class=&quot;key&quot;&gt;linkable&lt;/span&gt;: defaultLinkable,
        &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: classify(name)
      };
    } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (breadCrumbType === &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;;
    } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
      setProperties(breadCrumb, {
        path,
        &lt;span class=&quot;key&quot;&gt;linkable&lt;/span&gt;: breadCrumb.hasOwnProperty(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;linkable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) ? breadCrumb.linkable : defaultLinkable
      });
    }

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; breadCrumb;
  });

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; emberArray(filter(breadCrumbs, (breadCrumb) =&amp;gt; {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; typeOf(breadCrumb) !== &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
  }));
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Reconstructing the route name&lt;/h3&gt;

&lt;p&gt;Each time map runs in the previous method, we get a single piece of the route name, e.g. &lt;code&gt;bar&lt;/code&gt;. We know that its correct route name is &lt;code&gt;foo.bar&lt;/code&gt;, so we can slice the original array with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Syntax&quot;&gt;map&amp;#39;s &lt;code&gt;index&lt;/code&gt; argument&lt;/a&gt; to piece those bits together. When we start with the first piece (&lt;code&gt;foo&lt;/code&gt;), we know that we need to look up &lt;code&gt;foo.index&lt;/code&gt; so that we can generate the correct link-to, so we check for that.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_guessRoutePath(routeNames, name, index) {
  const routes = routeNames.slice(&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;, index + &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (routes.length === &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{name}.index&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;;
  } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; routes.join(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now that we have the correct route name for each path, we can look up the actual route object on the Container while we map over the filtered route names.&lt;/p&gt;

&lt;h3&gt;Looking up the route on the Container&lt;/h3&gt;

&lt;p&gt;The Ember Container (basically how Ember keeps track of all its different objects) isn&amp;#39;t well documented because it is originally intended to be private API. However, many addons and apps make use of it to do certain things, and this one is no exception. There is an &lt;a href=&quot;https://github.com/emberjs/rfcs/pull/46&quot;&gt;RFC on the table&lt;/a&gt; with reforming the Registry and Container, so this might have to be changed in the future. For now, we can still get the Container from the Component, and then use its &lt;code&gt;lookup(&amp;#39;type:name&amp;#39;)&lt;/code&gt; method to find the route.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_lookupRoute(routeName) {
  const container = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const route = container.lookup(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;route:&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{routeName}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
  assert(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;[ember-crumbly] &lt;span class=&quot;error&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;route:&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{routeName}&lt;span class=&quot;error&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt; was not found&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;, route);

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; route;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Extracting the breadCrumb POJO&lt;/h3&gt;

&lt;p&gt;With the route object in hand, we can then easily extract the &lt;code&gt;breadCrumb&lt;/code&gt; POJO we define on our routes.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let breadCrumb = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._lookupRoute(path).getWithDefault(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;breadCrumb&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;undefined&lt;/span&gt;);
const breadCrumbType = typeOf(breadCrumb);

&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (breadCrumbType === &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) {
  breadCrumb = {
    path,
    &lt;span class=&quot;key&quot;&gt;linkable&lt;/span&gt;: defaultLinkable,
    &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: classify(name)
  };
} &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (breadCrumbType === &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;;
} &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
  setProperties(breadCrumb, {
    path,
    &lt;span class=&quot;key&quot;&gt;linkable&lt;/span&gt;: breadCrumb.hasOwnProperty(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;linkable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) ? breadCrumb.linkable : defaultLinkable
  });
}

&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; breadCrumb;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In certain scenarios, you might want to opt-out of displaying a specific route in the breadcrumb. We allow that by setting &lt;code&gt;breadCrumb: null&lt;/code&gt; inside of that route. If no breadCrumb POJO is found, we set the title to be the route&amp;#39;s capitalized name by default, and if we do find one, we simply add the path and linkable keys to it.&lt;/p&gt;

&lt;p&gt;Finally, we return an &lt;a href=&quot;http://emberjs.com/api/classes/Ember.html#method_A&quot;&gt;Ember Array&lt;/a&gt; so that the resulting array is iterable in the template, and filter out any undefined breadcrumbs.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; emberArray(filter(breadCrumbs, (breadCrumb) =&amp;gt; {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; typeOf(breadCrumb) !== &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
}));
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With the logic done, let&amp;#39;s look at our somewhat complicated template to handle all the different uses!&lt;/p&gt;

&lt;h3&gt;Template logic&lt;/h3&gt;

&lt;p&gt;Because we want to handle both the inline and block form of the Component, as well as the ability to make each route linkable, the template does get a little complicated:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#each routeHierarchy as |route|}}
  &amp;lt;li class={{crumbClass}}&amp;gt;
    {{#if hasBlock}}
      {{#if route.linkable}}
        {{#link-to route.path}}
          {{yield this route}}
        {{/link-to}}
      {{else}}
        {{yield this route}}
      {{/if}}
    {{else}}
      {{#if route.linkable}}
        {{#link-to route.path}}
          {{route.title}}
        {{/link-to}}
      {{else}}
        {{route.title}}
      {{/if}}
    {{/if}}
  &amp;lt;/li&amp;gt;
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And that&amp;#39;s done!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post also appears on &lt;a href=&quot;https://medium.com/delightful-ui-for-ember-apps/declarative-breadcrumb-navigation-in-ember-js-5908a92a5de3&quot;&gt;Medium in longform&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Announcing Voorhees</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/05/29/announcing-voorhees" />
    <id>https://dockyard.com/blog/2015/05/29/announcing-voorhees</id>
    <category term="elixir" label="Elixir"/><category term="phoenix" label="Phoenix"/><category term="testing" label="Testing"/>
    <published>2015-05-29 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Voorhees is a library for testing Phoenix JSON APIs</summary>
    <content type="html">&lt;p&gt;I&amp;#39;ve been building JSON APIs in &lt;a href=&quot;http://www.phoenixframework.org&quot;&gt;Phoenix&lt;/a&gt; for
a few Ember apps I&amp;#39;ve been working on. I wanted to ensure that the JSON
response didn&amp;#39;t include extra information in the form of attributes that
should be kept server side, and returned the correct payload. We can break
these two concerns into separate tests, the first making sure that our JSON
response conforms to a specific &amp;quot;schema&amp;quot;, the other making sure that the
attributes that we care about are correct.
&lt;a href=&quot;https://github.com/danmcclain/voorhees&quot;&gt;Voorhees&lt;/a&gt;, named after &lt;a href=&quot;http://www.imdb.com/media/rm4040136960/ch0002146#&quot;&gt;JSON...I mean
Jason Voorhees&lt;/a&gt;, provides
functions for both of these concerns.&lt;/p&gt;

&lt;h2&gt;&lt;code&gt;Voorhees.matches_schema?&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Voorhees.matches_schema?(payload, expected_keys)&lt;/code&gt; makes sure that a payload
conforms to a certain format. You pass in a string that is the API response and
a list of keys to check it against. If that payload has extra keys, or the
payload is missing keys, the function returns &lt;code&gt;false&lt;/code&gt;, causing it to fail the
&lt;code&gt;assert&lt;/code&gt; in your test.&lt;/p&gt;

&lt;h3&gt;Examples&lt;/h3&gt;

&lt;p&gt;Validating simple objects&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S[{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: &amp;quot;baz&amp;quot; }]
iex&amp;gt; Voorhees.matches_schema?(payload, [:foo, &amp;quot;bar&amp;quot;]) # Property names can be strings or atoms
true

# Extra keys
iex&amp;gt; payload = ~S[{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: &amp;quot;baz&amp;quot;, &amp;quot;boo&amp;quot;: 3 }]
iex&amp;gt; Voorhees.matches_schema?(payload, [:foo, &amp;quot;bar&amp;quot;])
false

# Missing keys
iex&amp;gt; payload = ~S[{ &amp;quot;foo&amp;quot;: 1 }]
iex&amp;gt; Voorhees.matches_schema?(payload, [:foo, &amp;quot;bar&amp;quot;])
false
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Validating lists of objects&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S/[{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: &amp;quot;baz&amp;quot; },{ &amp;quot;foo&amp;quot;: 2, &amp;quot;bar&amp;quot;: &amp;quot;baz&amp;quot; }]/
iex&amp;gt; Voorhees.matches_schema?(payload, [:foo, &amp;quot;bar&amp;quot;])
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Validating nested lists of objects&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S/{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: [{ &amp;quot;baz&amp;quot;: 2 }]}/
iex&amp;gt; Voorhees.matches_schema?(payload, [:foo, bar: [:baz]])
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Validating that a property is a list of scalar values&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S/{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: [&amp;quot;baz&amp;quot;, 2]}/
iex&amp;gt; Voorhees.matches_schema?(payload, [:foo, bar: []])
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;&lt;code&gt;Voorhees.matches_payload?&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Voorhees.matches_payload?(payload, expected_payload)&lt;/code&gt; makes sure that a payload
contains the right values. It should be used in conjuction with
&lt;code&gt;Voorhees.matches_schema?/2&lt;/code&gt;. &lt;code&gt;Voorhees.matches_payloads?&lt;/code&gt; ignores values that
are present in the &lt;code&gt;payload&lt;/code&gt; but not in the &lt;code&gt;expected_payload&lt;/code&gt;; this allows you
to ignore server generated values, like &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;created_at&lt;/code&gt; timestamps. You
may not necessarily care about the values of these server generated attributes.
It will return &lt;code&gt;false&lt;/code&gt; when a value in &lt;code&gt;expected_payload&lt;/code&gt; is missing from the
&lt;code&gt;payload&lt;/code&gt;, or when the values in the &lt;code&gt;payload&lt;/code&gt; differ from the &lt;code&gt;expected_payload&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Examples&lt;/h3&gt;

&lt;p&gt;Expected payload keys can be either strings or atoms&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S[{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: &amp;quot;baz&amp;quot; }]
iex&amp;gt; Voorhees.matches_payload?(payload, %{ :foo =&amp;gt; 1, &amp;quot;bar&amp;quot; =&amp;gt; &amp;quot;baz&amp;quot; })
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Extra key/value pairs in payload are ignored&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S[{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: &amp;quot;baz&amp;quot;, &amp;quot;boo&amp;quot;: 3 }]
iex&amp;gt; Voorhees.matches_payload?(payload, %{ :foo =&amp;gt; 1, &amp;quot;bar&amp;quot; =&amp;gt; &amp;quot;baz&amp;quot; })
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Extra key/value pairs in expected payload cause the validation to fail&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S[{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: &amp;quot;baz&amp;quot;}]
iex&amp;gt; Voorhees.matches_payload?(payload, %{ :foo =&amp;gt; 1, &amp;quot;bar&amp;quot; =&amp;gt; &amp;quot;baz&amp;quot;, :boo =&amp;gt; 3 })
false
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Validates scalar lists&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S/{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: [&amp;quot;baz&amp;quot;]}/
iex&amp;gt; Voorhees.matches_payload?(payload, %{ :foo =&amp;gt; 1, &amp;quot;bar&amp;quot; =&amp;gt; [&amp;quot;baz&amp;quot;] })
true

# Order is respected
iex&amp;gt; payload = ~S/{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: [1, &amp;quot;baz&amp;quot;]}/
iex&amp;gt; Voorhees.matches_payload?(payload, %{ :foo =&amp;gt; 1, &amp;quot;bar&amp;quot; =&amp;gt; [&amp;quot;baz&amp;quot;, 1] })
false
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Validates lists of objects&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S/[{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: { &amp;quot;baz&amp;quot;: 2 }}]/
iex&amp;gt; Voorhees.matches_payload?(payload, [%{ :foo =&amp;gt; 1, &amp;quot;bar&amp;quot; =&amp;gt; %{ &amp;quot;baz&amp;quot; =&amp;gt; 2 } }])
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Validates nested objects&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S/{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: { &amp;quot;baz&amp;quot;: 2 }}/
iex&amp;gt; Voorhees.matches_payload?(payload, %{ :foo =&amp;gt; 1, &amp;quot;bar&amp;quot; =&amp;gt; %{ &amp;quot;baz&amp;quot; =&amp;gt; 2 } })
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Validates nested lists of objects&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;iex&amp;gt; payload = ~S/{ &amp;quot;foo&amp;quot;: 1, &amp;quot;bar&amp;quot;: [{ &amp;quot;baz&amp;quot;: 2 }]}/
iex&amp;gt; Voorhees.matches_payload?(payload, %{ :foo =&amp;gt; 1, &amp;quot;bar&amp;quot; =&amp;gt; [%{ &amp;quot;baz&amp;quot; =&amp;gt; 2 }] })
true
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Take a machete to your API responses&lt;/h2&gt;

&lt;p&gt;Make sure your API responses are what you expect, or cut them down at the knees when your tests fail!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Begin with Benchmarking</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/05/22/begin-with-benchmarking" />
    <id>https://dockyard.com/blog/2015/05/22/begin-with-benchmarking</id>
    <category term="design-research" label="Design Research"/><category term="benchmarking" label="Benchmarking"/><category term="design-strategy" label="Design Strategy"/>
    <published>2015-05-22 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Ashley Treni</name></author>
    <summary>Utilizing design research strategies</summary>
    <content type="html">&lt;p&gt;Design research is critical to the beginning stage of every design project. Research orients us in the world in which we intend to build and the audience we intend to build for. It is helpful to begin by identifying other services that already exist in that space, to observe the current market offerings. Building a research catalog for reference and critique is what we refer to as &amp;quot;benchmarking.&amp;quot;&lt;/p&gt;

&lt;p&gt;Here are three major benefits to benchmarking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It helps you better understand and articulate how your product or service is different&lt;/li&gt;
&lt;li&gt;It is a tool for learning about topics you might not be familiar with (especially for client projects)&lt;/li&gt;
&lt;li&gt;It allows you to observe strengths and weaknesses of existing experiences to inform your own design decisions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At DockYard, we always begin with benchmarking. Benchmarking helps us define a scope based on realistic expectations, and identify opportunities and core values for the project. It is a way to learn through exploration. In this practice and analysis we deconstruct existing complex systems, identify the minimum viable product and core interactions, and pinpoint the major actions that support user goals. &lt;/p&gt;

&lt;p&gt;These exercises give us a better understanding of the space we intend to support, and the expectations for building a system of our own. It sets a focus and direction for ideation and user interviews, and aligns our understanding with the client&amp;#39;s, which supports conversation.&lt;/p&gt;

&lt;p&gt;There are several different layers to observe in a given case study from structural to aesthetic: content organization, accessibility, systems architecture, user experience methods, interface design, to visual design. It can be challenging to observe all these different layers and identify what about them creates a quality online experience.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Start broad. Identify the overall goal of the service that brings you from A to B. Is that process transparent and supportive? Were you able to easily use the product and accomplish the task at hand? Is the information accessible? How is it organized and delivered?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Look at the usability and interactions. Do the interactions make sense in context? Is the structure intuitive, clear, and easy to use? Are design patterns present: experiential, cognitive, tangible ways that help users interact with the interface? Identifying these patterns in context helps us understand where they can be used to support user interactions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consider the visual design and experience. What is the quality of the experience, and does it reflect the overall goal of the service? Is it delightful? confusing? distracting? Does the visual language and style support understanding?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Benchmarking isn&amp;#39;t about taking someone else&amp;#39;s solution and using it as your own. Every project has different content, different goals, different challenges. Deconstructing existing design solutions is key to identifying structural and experiential decisions, and reflecting on why those decisions were made to support the task at hand. This kind of critical thinking allows us to be discerning, to ask questions about how others have solved problems in similar spaces, so that we can anticipate and identify the major goals for the system we intend to build.&lt;/p&gt;

&lt;p&gt;Through intentionally observing systems and strategies, we adopt a perpetually observant and critical mindset. The benchmarking mentality encourages us to pay attention to and appreciate the complexity of data driven web experiences, and to see how the challenges of vision, architecture, and experience were met and resolved.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Sign Up For The DockYard Newsletter</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/05/21/sign-up-for-the-dockyard-newsletter" />
    <id>https://dockyard.com/blog/2015/05/21/sign-up-for-the-dockyard-newsletter</id>
    <category term="business" label="Business"/><category term="announcement" label="Announcement"/>
    <published>2015-05-21 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;We are now running a monthly newsletter, we&amp;#39;ll send currated design and
engineering content directly to your Inbox. The best articles from our
blog as well as exclusive content that we&amp;#39;ll only publish in the monthly
newsletter.&lt;/p&gt;

&lt;p&gt;You can sign up at the bottom of this page!&lt;/p&gt;
</content>
  </entry><entry>
    <title>The New DockYard.com</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/05/20/the-new-dockyard-dot-com" />
    <id>https://dockyard.com/blog/2015/05/20/the-new-dockyard-dot-com</id>
    <category term="business" label="Business"/><category term="announcement" label="Announcement"/>
    <published>2015-05-20 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I&amp;#39;m proud to announce the new &lt;a href=&quot;https://dockyard.com&quot;&gt;DockYard.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/D3KeY1b.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;With this relaunch of our website we are also changing our direction as
a company. We&amp;#39;ve always been considered an &lt;em&gt;engineering&lt;/em&gt; company but we
are now considering ourselves a &lt;strong&gt;User Experience&lt;/strong&gt; company. All of
our design and engineering decisions go into delivering a modern user
experience on the web for our clients.&lt;/p&gt;

&lt;p&gt;This new website is also built how we believe modern web applications
should be built: with &lt;a href=&quot;http://emberjs.com&quot;&gt;Ember.js&lt;/a&gt; on the front-end
and &lt;a href=&quot;http://phoenixframework.org&quot;&gt;Phoenix&lt;/a&gt; on the back-end. &lt;/p&gt;

&lt;p&gt;Over the next few weeks we&amp;#39;re going to share the story of how our team rebuilt
DockYard.com. You&amp;#39;ll hear from our Creative Director &lt;a href=&quot;http://twitter.com/strevat&quot;&gt;Steven Trevathan&lt;/a&gt; on
what went into the Discovery of our new website, the design decisions
made, as well as a view of some early mockups and how we came to the
final design. &lt;a href=&quot;http://twitter.com/_danmcclain&quot;&gt;Dan McClain&lt;/a&gt;, the head of our Engineering team will discuss
how we built our Ember application the &amp;quot;DockYard Way&amp;quot; which meant we
had to make contributions back to Ember itself, as well as
several other libraries, in order to get the experience just right.
&lt;a href=&quot;http://twitter.com/acacheung&quot;&gt;Amanda Cheung&lt;/a&gt;, our Lead UX Developer, will share what efforts went into the implementation of
the design; how we build modern responsive markup. Finally you&amp;#39;ll hear
from &lt;a href=&quot;http://twitter.com/jon_lacks&quot;&gt;Jon Lacks&lt;/a&gt;, our Project Manager, who will show how we managed the rebuild
of our own website using the exact same processes we use on our client
projects.&lt;/p&gt;

&lt;p&gt;Along with these stories we&amp;#39;ll not just tell you how we did things, we
plan to show you. We&amp;#39;ll be open sourcing all of the code for the Ember
front-end as well as the Phoenix back-end in the coming weeks. There are
also many libraries that we plan to extract from the application to
share with everyone.&lt;/p&gt;

&lt;p&gt;I&amp;#39;m extremely proud of the team for delivering this rebuild. It is the
best example of the quality and integrity of our design and technical
capabilities to date.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Detecting Ember.js Components Entering or Leaving the Viewport</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/04/20/ember-in-viewport" />
    <id>https://dockyard.com/blog/2015/04/20/ember-in-viewport</id>
    <category term="ember" label="Ember.js"/><category term="addon" label="Addon"/><category term="javascript" label="JavaScript"/>
    <published>2015-04-20 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Lauren Tan</name></author>
    <summary>I wrote a post last year about how I made an Ember Mixin that would let Ember Components or Views know if their DOM element had entered or left the viewport. This time, I want to talk about how I improved the original Mixin to use the requestAnimationFrame API for improved performance at close to 60FPS.</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;This concise version originally appears on &lt;a href=&quot;https://medium.com/delightful-ui-for-ember-apps/creating-an-ember-cli-addon-detecting-ember-js-components-entering-or-leaving-the-viewport-7d95ceb4f5ed&quot;&gt;Medium in longform&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I &lt;a href=&quot;https://medium.com/delightful-ui-for-ember-apps/ember-js-detecting-if-a-dom-element-is-in-the-viewport-eafcc77a6f86&quot;&gt;wrote a post&lt;/a&gt;
last year about how I made an Ember Mixin that would let Ember Components or
Views know if their DOM element had entered or left the viewport. If you&amp;#39;re
unfamiliar with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect&quot;&gt;&lt;code&gt;getBoundingClientRect&lt;/code&gt;&lt;/a&gt;
API or the approach in general (for determining if an element is in the
viewport), please have a read of that post first!&lt;/p&gt;

&lt;p&gt;This time, I want to talk about how I improved the original Mixin to use the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame&quot;&gt;&lt;code&gt;requestAnimationFrame&lt;/code&gt;&lt;/a&gt;
API for improved performance at close to 60FPS. Because
&lt;a href=&quot;http://caniuse.com/#search=requestAnimationFrame&quot;&gt;certain browsers&lt;/a&gt; (mainly IE)
don&amp;#39;t support &lt;code&gt;rAF&lt;/code&gt;, we&amp;#39;ll also setup an automatic fallback to using the Ember
run loop method I used in my previous post.&lt;/p&gt;

&lt;h2&gt;Demo&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://d262ilb51hltx0.cloudfront.net/max/1600/1*9WZqJfpL4daIEBJiufTolQ.png&quot; alt=&quot;Featuring Brian&quot;&gt;&lt;/p&gt;

&lt;p&gt;I made a simple &lt;a href=&quot;http://development.ember-in-viewport-demo.divshot.io/&quot;&gt;demo app&lt;/a&gt;
to demonstrate how you might use the Mixin. The goal for this addon was to allow
you to easily style or do something with Components/Views when they enter or
leave the viewport. For example, you could easily use this Mixin to build a
lazy loader for images, or even for triggering animations. Using this Mixin,
you won&amp;#39;t need to use a jQuery plugin and can instead rely on a highly
performant ember-cli addon.&lt;/p&gt;

&lt;h2&gt;Installing the addon&lt;/h2&gt;

&lt;p&gt;If you&amp;#39;re using ember-cli and want to use the addon, you can install it with:&lt;/p&gt;
&lt;div class=&quot;highlight shell &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ ember install ember-in-viewport
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The source for the addon is available at &lt;a href=&quot;https://github.com/dockyard/ember-in-viewport&quot;&gt;dockyard/ember-in-viewport&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Rewriting the In Viewport Mixin&lt;/h2&gt;

&lt;p&gt;The Mixin still uses the &lt;a href=&quot;https://medium.com/delightful-ui-for-ember-apps/ember-js-detecting-if-a-dom-element-is-in-the-viewport-eafcc77a6f86&quot;&gt;same method&lt;/a&gt;
for determining if a DOM element is in the viewport, using
&lt;code&gt;getBoundingClientRect&lt;/code&gt; and the window&amp;#39;s &lt;code&gt;innerHeight&lt;/code&gt; and &lt;code&gt;innerWidth&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Updating the Is In Viewport logic&lt;/h3&gt;

&lt;p&gt;The method for calculating whether or not a DOM element is in the viewport
remains mostly unchanged, except with the addition of a new &lt;code&gt;viewportTolerance&lt;/code&gt;
argument.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

const { merge } = Ember;

const defaultTolerance = {
  &lt;span class=&quot;key&quot;&gt;top&lt;/span&gt;    : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;left&lt;/span&gt;   : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;bottom&lt;/span&gt; : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;right&lt;/span&gt;  : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;
};

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;isInViewport&lt;/span&gt;(boundingClientRect={}, height=&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;, width=&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;, tolerance=defaultTolerance) {
  const { top, left, bottom, right } = boundingClientRect;
  const tolerances = merge(defaultTolerance, tolerance);
  let {
    &lt;span class=&quot;key&quot;&gt;top&lt;/span&gt;    : topTolerance,
    &lt;span class=&quot;key&quot;&gt;left&lt;/span&gt;   : leftTolerance,
    &lt;span class=&quot;key&quot;&gt;bottom&lt;/span&gt; : bottomTolerance,
    &lt;span class=&quot;key&quot;&gt;right&lt;/span&gt;  : rightTolerance
  } = tolerances;

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; (
    (top + topTolerance)       &amp;gt;= &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp;
    (left + leftTolerance)     &amp;gt;= &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp;
    (bottom - bottomTolerance) &amp;lt;= height &amp;amp;&amp;amp;
    (right - rightTolerance)   &amp;lt;= width
  );
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With the addition of the &lt;code&gt;viewportTolerance&lt;/code&gt; option, addon users can relax how
precise the check is. When set to &lt;code&gt;0&lt;/code&gt;, the Mixin only considers an element
inside the viewport when it is completely visible inside of the viewport.&lt;/p&gt;

&lt;h3&gt;Setting up the Class variables&lt;/h3&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const {
  get,
  set,
  setProperties,
  computed,
  run,
  on,
  &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;,
} = Ember;

const {
  scheduleOnce,
  debounce,
  bind,
  next
} = run;

const { not }     = computed;
const { forEach } = Ember.EnumerableUtils;

const listeners = [
  { &lt;span class=&quot;key&quot;&gt;context&lt;/span&gt;: window,   &lt;span class=&quot;key&quot;&gt;event&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;scroll.scrollable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; },
  { &lt;span class=&quot;key&quot;&gt;context&lt;/span&gt;: window,   &lt;span class=&quot;key&quot;&gt;event&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;resize.resizable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; },
  { &lt;span class=&quot;key&quot;&gt;context&lt;/span&gt;: document, &lt;span class=&quot;key&quot;&gt;event&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;touchmove.scrollable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }
];

let rAFIDS = {};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you haven&amp;#39;t had the chance to use &lt;a href=&quot;https://babeljs.io/docs/learn-es6/&quot;&gt;ES2015 features&lt;/a&gt;,
now&amp;#39;s a good time to learn, since &lt;code&gt;ember-cli-babel&lt;/code&gt; has been shipped with
ember-cli by default for a while now. Here, we&amp;#39;re destructuring certain methods
from Ember, as well as setting up an array of listeners we want to register. I
also declare a mutable variable &lt;code&gt;rAFIDS&lt;/code&gt; with &lt;code&gt;let&lt;/code&gt;âââI&amp;#39;ll be using this object
to store the ID that&amp;#39;s returned by &lt;code&gt;requestAnimationFrame&lt;/code&gt; so that we can cancel
it later.&lt;/p&gt;

&lt;p&gt;Something interesting to note is that these variables are actually shared by all
instances of the Mixin. This means if we stored the ID in that variable, it would
be overwritten by other instances of the Components that are being watched by
the Mixin. So instead, we&amp;#39;ll store each ID as a key (the element ID for the
Component) inside of an object. More on that later.&lt;/p&gt;

&lt;h3&gt;Initial state&lt;/h3&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_setInitialState: on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  setProperties(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, {
    &lt;span class=&quot;predefined&quot;&gt;$viewportCachedEl&lt;/span&gt;   : &lt;span class=&quot;predefined-constant&quot;&gt;undefined&lt;/span&gt;,
    &lt;span class=&quot;key&quot;&gt;viewportUseRAF&lt;/span&gt;      : canUseRAF(),
    &lt;span class=&quot;key&quot;&gt;viewportEntered&lt;/span&gt;     : &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;key&quot;&gt;viewportSpy&lt;/span&gt;         : &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;key&quot;&gt;viewportRefreshRate&lt;/span&gt; : &lt;span class=&quot;integer&quot;&gt;100&lt;/span&gt;,
    &lt;span class=&quot;key&quot;&gt;viewportTolerance&lt;/span&gt;   : {
      &lt;span class=&quot;key&quot;&gt;top&lt;/span&gt;    : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;left&lt;/span&gt;   : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;bottom&lt;/span&gt; : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;right&lt;/span&gt;  : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;
    },
  });
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We&amp;#39;ll need to setup some initial values for our Mixin&amp;#39;s state. We do this when
the Object the Mixin is mixed into is instantiated, by setting some properties
on &lt;code&gt;init&lt;/code&gt;. This is because &lt;a href=&quot;http://emberjs.com/api/classes/Ember.Mixin.html&quot;&gt;Mixins extend a constructor&amp;#39;s prototype&lt;/a&gt;,
so certain properties will be shared amongst objects that implement the Mixinâââ
and in our case, we want these to be unique to each instance.&lt;/p&gt;

&lt;p&gt;Here, we&amp;#39;re also going to make use of our utility function &lt;a href=&quot;https://github.com/dockyard/ember-in-viewport/blob/0.2.1/addon/utils/can-use-raf.js&quot;&gt;&lt;code&gt;canUseRAF&lt;/code&gt;&lt;/a&gt;
to let the Mixin know whether to use &lt;code&gt;requestAnimationFrame&lt;/code&gt; or fallback to the
Ember run loop.&lt;/p&gt;

&lt;h3&gt;Setting up the DOM element rendered by the component&lt;/h3&gt;

&lt;p&gt;When the DOM element is inserted, we&amp;#39;ll need to do a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The initial check on render to see if the element is immediately in view&lt;/li&gt;
&lt;li&gt;Setting up an observer to unbind listeners if we&amp;#39;re not spying on the element&lt;/li&gt;
&lt;li&gt;Calling the recursive &lt;code&gt;requestAnimationFrame&lt;/code&gt; method&lt;/li&gt;
&lt;li&gt;Setting up event listeners if we are spying on the element&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_setupElement: on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;didInsertElement&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (!canUseDOM) { &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt;; }

  const viewportUseRAF = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportUseRAF&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._setInitialViewport(window);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._addObserverIfNotSpying();
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._setViewportEntered(window);

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (!viewportUseRAF) {
    forEach(listeners, (listener) =&amp;gt; {
      const { context, event } = listener;
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._bindListeners(context, event);
    });
  }
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Checking if the DOM element is immediately in view&lt;/h3&gt;

&lt;p&gt;After the element has been rendered into the DOM, we want to immediately check
if it&amp;#39;s visible. This calls the &lt;code&gt;_setViewportEntered&lt;/code&gt; method in the
&lt;code&gt;afterRender&lt;/code&gt; queue of the Ember run loop, which ensures that the DOM element
is actually already inserted and available for us.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_setInitialViewport(context=&lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;) {
  Ember.assert(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;You must pass a valid context to _setInitialViewport&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, context);

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; scheduleOnce(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;afterRender&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, () =&amp;gt; {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._setViewportEntered(context);
  });
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Unbinding listeners after entering the viewport&lt;/h3&gt;

&lt;p&gt;It makes sense in certain use cases to stop watching the element after it has
entered the viewport &lt;em&gt;at least once&lt;/em&gt;. For example, in an image lazy loader, we
only want to load the image once, after which it makes sense to clean up
listeners to reduce the load on the app. We do that with the &lt;code&gt;viewportSpy&lt;/code&gt;
option.&lt;/p&gt;

&lt;p&gt;Here, we programatically add an observer on the &lt;code&gt;viewportEntered&lt;/code&gt; prop if
&lt;code&gt;viewportSpy&lt;/code&gt; has been set to &lt;code&gt;false&lt;/code&gt; by our addon user. The observer itself
doesn&amp;#39;t do muchâââit unbinds listeners and then removes itself.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_addObserverIfNotSpying() {
  const viewportSpy = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportSpy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (!viewportSpy) {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.addObserver(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportEntered&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._viewportDidEnter);
  }
},

_viewportDidEnter() {
  const viewportEntered = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportEntered&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const viewportSpy     = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportSpy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (!viewportSpy &amp;amp;&amp;amp; viewportEntered) {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._unbindListeners();
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.removeObserver(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportEntered&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._viewportDidEnter);
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Setting up event listeners&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s look at binding our event listeners before we take a look at
&lt;code&gt;_setViewportEntered&lt;/code&gt;, the main method for the mixin. We&amp;#39;ll be using the array
of listeners we declared earlier at the top of the file, and binding the event
to the appropriate context (&lt;code&gt;window&lt;/code&gt; or &lt;code&gt;document&lt;/code&gt;), like so:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_bindListeners(context=&lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;, event=&lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;) {
  Ember.assert(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;You must pass a valid context to _bindListeners&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, context);
  Ember.assert(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;You must pass a valid event to _bindListeners&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, event);

  const elementId = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  Ember.warn(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;No elementId was found on this Object, `viewportSpy` will&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; +
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;not work as expected&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, elementId);

  &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(context).on(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{event}&lt;span class=&quot;error&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{elementId}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;, () =&amp;gt; {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._scrollHandler(context);
  });
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note that we can actually pass the Component&amp;#39;s &lt;a href=&quot;http://emberjs.com/api/classes/Ember.View.html#property_elementId&quot;&gt;&lt;code&gt;elementId&lt;/code&gt;&lt;/a&gt;
(the &lt;code&gt;id&lt;/code&gt; attribute that is rendered into the DOM) to the event, which will
allow us to only unbind the listener for that particular element. If we didn&amp;#39;t
do this, all listeners would have been unbound when the first DOM element enters
the viewport, which isn&amp;#39;t what we&amp;#39;d want.&lt;/p&gt;

&lt;h3&gt;Handling the event&lt;/h3&gt;

&lt;p&gt;Now, we can handle the event by debouncing the main method with the
&lt;code&gt;viewportRefreshRate&lt;/code&gt; set by the addon user.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_scrollHandler(context=&lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;) {
  Ember.assert(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;You must pass a valid context to _scrollHandler&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, context);

  const viewportRefreshRate = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportRefreshRate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  debounce(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._setViewportEntered(context);
  }, viewportRefreshRate);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Unbinding listeners&lt;/h3&gt;

&lt;p&gt;When we eventually destroy the Component, we want to make sure we also cleanup
after ourselves. We&amp;#39;ll have to remove both event listeners and the recursive
&lt;code&gt;requestAnimationFrame&lt;/code&gt; call:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_unbindListeners() {
  const elementId      = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const viewportUseRAF = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportUseRAF&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  Ember.warn(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;No elementId was found on this Object, `viewportSpy` will&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; +
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;not work as expected&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, elementId);

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (viewportUseRAF) {
    next(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, () =&amp;gt; {
      window.cancelAnimationFrame(rAFIDS[elementId]);
      rAFIDS[elementId] = &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;;
    });
  }

  forEach(listeners, (listener) =&amp;gt; {
    const { context, event } = listener;
    &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(context).off(&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{event}&lt;span class=&quot;error&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;{elementId}&lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;);
  });
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_teardown: on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;willDestroyElement&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._unbindListeners();
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you recall, the &lt;code&gt;requestAnimationFrame&lt;/code&gt; function returns an ID that uniquely
identifies the entry in the callback list. We can pass this on to
&lt;code&gt;cancelAnimationFrame&lt;/code&gt; in order to cancel the infinitely recursive call to the
main method. Because we register the Component&amp;#39;s DOM &lt;code&gt;elementId&lt;/code&gt; as a key in the
&lt;code&gt;rAFIDS&lt;/code&gt; object, we can remove the specific rAF call for that single Component.
I&amp;#39;ve wrapped the cAF call in an &lt;code&gt;Ember.run.next&lt;/code&gt; to avoid a race condition that
happens occasionally.&lt;/p&gt;

&lt;h3&gt;Updating the viewportEntered property&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s take a look at the main method responsible for setting the
&lt;code&gt;viewportEntered&lt;/code&gt; property. This method does two main things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;viewportEntered&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Fire off the next &lt;code&gt;requestAnimationFrame&lt;/code&gt; step&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;_setViewportEntered(context=&lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;) {
  Ember.assert(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;You must pass a valid context to _setViewportEntered&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, context);

  const &lt;span class=&quot;predefined&quot;&gt;$viewportCachedEl&lt;/span&gt; = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;$viewportCachedEl&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const viewportUseRAF    = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportUseRAF&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const elementId         = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const tolerance         = get(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportTolerance&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  const height            = &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(context) ? &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(context).height() : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;;
  const width             = &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(context) ? &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(context).width()  : &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;;

  let boundingClientRect;

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;predefined&quot;&gt;$viewportCachedEl&lt;/span&gt;) {
    boundingClientRect = &lt;span class=&quot;predefined&quot;&gt;$viewportCachedEl&lt;/span&gt;[&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;].getBoundingClientRect();
  } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
    boundingClientRect = set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;$viewportCachedEl&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;())[&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;].getBoundingClientRect();
  }

  const viewportEntered = isInViewport(boundingClientRect, height, width, tolerance);

  set(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;viewportEntered&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, viewportEntered);

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;predefined&quot;&gt;$viewportCachedEl&lt;/span&gt; &amp;amp;&amp;amp; viewportUseRAF) {
    rAFIDS[elementId] = window.requestAnimationFrame(
      bind(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._setViewportEntered, context)
    );
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As a simple optimization, we can cache the selected DOM element inside the
Object as &lt;code&gt;$viewportCachedEl&lt;/code&gt; so we don&amp;#39;t have call the expensive DOM node
selector method every time. Then, we pass the Component&amp;#39;s element properties to
the utility we defined earlier, and set the &lt;code&gt;viewportEntered&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;requestAnimationFrame&lt;/code&gt; is enabled, we call the method again inside of the
rAF method, after binding it to the correct context. Like
&lt;code&gt;Function.prototype.bind&lt;/code&gt;, this creates a new function, that when called, has
its &lt;code&gt;this&lt;/code&gt; keyword set to the correct value (along with any arguments). With
that first call after the element is inserted into the DOM, this fires off an
infinitely recursive loop that will only end when we cancel it.&lt;/p&gt;

&lt;p&gt;Hence, we don&amp;#39;t have to setup event listeners when rAF is enabled. And that&amp;#39;s it
for the Mixin!&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Beginner&#39;s Fallacy</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/04/10/the-beginners-fallacy" />
    <id>https://dockyard.com/blog/2015/04/10/the-beginners-fallacy</id>
    <category term="opinion" label="Opinion"/>
    <published>2015-04-10 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Helping onboard beginners is a hot topic right now in software
development. It is very good that this is important to people as we need
new software developers. However, I have noticed that many of these
developers are finding it difficult advancing beyond beginner. This
is especially evident when they are taken out of their current
development environment.&lt;/p&gt;

&lt;p&gt;Beginners require guidance and a set of rules to follow. This has been
shown time over time to be an effective strategy for learning. The
rules/principles/laws, whatever you want to call them, are based upon
the experience of more advanced developers that essentially boil down to 
&amp;quot;here is what you want to do &lt;em&gt;most&lt;/em&gt; of the time&amp;quot;. They are a great
substitute for experience. They also fit in very nicely with the notion
of &lt;strong&gt;Convention Over Configuration&lt;/strong&gt;. But unless you are stepping
outside of your framework the advantage of COC may turn into a career
hindering disadvantage.&lt;/p&gt;

&lt;p&gt;I am a big fan of Convention Over Configuration. I was first exposed to
it with Ruby on Rails and I like that Ember.js has been
following this path as well. However, I also believe that it can become
a crutch for beginners. The rules that they are following coupled with
the low friction environment of COC leads to a developer experience that
does not present too many obstacles to be overcome. Learning requires
challenge. You meet a challenge, you learn how to overcome that
challenge, you move on and now that experience is a tool you can wield in
the future.&lt;/p&gt;

&lt;p&gt;The market being flooded with beginners along with COC frameworks should
produce an environment that is heavily favored towards employers. (buyer&amp;#39;s market) 
In most cases these developers will be
able to accomplish most of what a very experienced developer can
accomplish. This is great for the company&amp;#39;s bottom line but not so good
for the individual developer&amp;#39;s own career growth.&lt;/p&gt;

&lt;p&gt;Instead, if you are interested in advancing beyond being a beginner,
you must get out of your comfort zone. This is going to require you to
put more time into your craft than your job necessarily allows. Try new
software languages, try old software languages. Go read
&lt;a href=&quot;https://mitpress.mit.edu/sicp/&quot;&gt;SICP&lt;/a&gt;. Attend meetups, &lt;a href=&quot;https://github.com/papers-we-love/papers-we-love&quot;&gt;read
papers&lt;/a&gt;,
contribute to open source. &lt;em&gt;Contribute to open source even if you think
your PR won&amp;#39;t be accepted&lt;/em&gt;. All of these things will take you out of the
comfort zone that your daily work gives you, but you&amp;#39;ll grow and become
a better (and more in demand) developer for it.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Importance of Being Experience First</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/04/09/the-importance-of-being-experience-first" />
    <id>https://dockyard.com/blog/2015/04/09/the-importance-of-being-experience-first</id>
    <category term="design" label="Design"/><category term="engineering" label="Engineering"/><category term="user-experience" label="User Experience"/><category term="opinion" label="Opinion"/>
    <published>2015-04-09 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Lauren Tan</name></author>
    <summary>Why being Experience First is more critical than ever â will the rise of website builders threaten the future of software consulting?</summary>
    <content type="html">&lt;p&gt;We&amp;#39;re in the middle of a digital renaissance that has software eating the world.
Like the industrial revolution, the digital revolution might see us eventually
becoming obsolete, but that&amp;#39;s okay because that&amp;#39;s what progress looks like. To
stay relevant, we need to place the Experience First.&lt;/p&gt;

&lt;h2&gt;The architects of the digital world&lt;/h2&gt;

&lt;p&gt;The modern architect has her roots in ancient and medieval history. They
originated as artisans; master craftsmen such as stone masons and carpenters.
In ancient times, there was no clear separation between the role of the
architect and the engineer â they were seen as one and the same.&lt;/p&gt;

&lt;p&gt;In some ways, the architects of the digital world are similar to those of the
physical. There are many parallels between the two, although it&amp;#39;s important to
be aware of leaky abstractions, and that they are only &lt;em&gt;similar&lt;/em&gt;, not exactly
the same.&lt;/p&gt;

&lt;h2&gt;The craftsmens&amp;#39; renaissance&lt;/h2&gt;

&lt;p&gt;We&amp;#39;re currently living in an age of digital renaissance.
&lt;a href=&quot;http://www.wsj.com/articles/SB10001424053111903480904576512250915629460&quot;&gt;Software is eating the world&lt;/a&gt;,
and some of us believe that we&amp;#39;re right in the middle of a great technological
revolution â the software revolution.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It&amp;#39;s no longer enough to build a good product or service. The world demands
excellence, because good is the new average.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I believe it&amp;#39;s partly a symptom of how efficient manufacturing has become, that
we&amp;#39;re experiencing wide scale &lt;a href=&quot;http://www.rushkoff.com/blog/2005/9/4/commodified-vs-commoditized.html&quot;&gt;commoditization&lt;/a&gt;
of goods and services that were historically considered luxuries. Because of
this, we&amp;#39;re also at the start of a new renaissance â one in which there is a
resurgence of an appreciation for &lt;a href=&quot;http://www.launch.co/blog/the-age-of-excellence.html/&quot;&gt;well designed experiences&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my &lt;a href=&quot;http://confreaks.tv/videos/emberconf2015-ambitious-ux-for-ambitious-apps&quot;&gt;EmberConf talk&lt;/a&gt;,
I defined design to mean more than aesthetics; design is how
things work, and encompasses the &lt;em&gt;entire experience&lt;/em&gt; across different mediums.
Airbnb calls this being &lt;a href=&quot;http://www.wired.com/2015/01/airbnbs-new-head-design-believes-design-led-companies-dont-work/&quot;&gt;Experience First&lt;/a&gt;,
as opposed to Design First, which suggests that anyone who isn&amp;#39;t a designer has
their contributions take a backseat.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;quot;That experience is essentially a story, a narrative which ultimately enjoins
us to a brand.&amp;quot; â &lt;a href=&quot;https://gigaom.com/2013/10/22/square-airbnb-and-why-experience-really-is-design/&quot;&gt;Om Malik, Gigaom&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, itâs obvious that we place value on things that fulfill both
form and function. The popularity of beautiful user experiences, both online and
offline, are the expression of a digital renaissance that is only going to
continue growing.&lt;/p&gt;

&lt;h2&gt;The rise of website builders and what it means for us&lt;/h2&gt;

&lt;p&gt;Unlike classical portrait painters, bowling alley pinsetters and other
jobs that have become redundant, the digital creator seems to be relatively
safe.&lt;/p&gt;

&lt;p&gt;With the rise of website builders like &lt;a href=&quot;https://thegrid.io/&quot;&gt;Wix&lt;/a&gt;,
&lt;a href=&quot;http://www.squarespace.com/&quot;&gt;Squarespace&lt;/a&gt;, &lt;a href=&quot;https://thegrid.io&quot;&gt;The Grid&lt;/a&gt; and
portfolio/shop builders like &lt;a href=&quot;http://www.shopify.com/&quot;&gt;Shopify&lt;/a&gt;,
&lt;a href=&quot;https://www.bigcommerce.com/&quot;&gt;BigCommerce&lt;/a&gt; and &lt;a href=&quot;http://virb.com/&quot;&gt;Virb&lt;/a&gt; though,
it&amp;#39;s easier than ever for an individual or business to get a beautiful looking
website created at a fraction of the cost.&lt;/p&gt;

&lt;p&gt;The beauty of the web is that once an asset has been made, it effectively costs
nothing to clone. A designer with a copy of Sketch or Photoshop can very quickly
design a &amp;#39;theme&amp;#39;, have it converted into HTML/CSS by a &amp;quot;PSD to HTML&amp;quot; service
(as they&amp;#39;re commonly known), and then sell it on one of these site builders.
You could very easily get a beautiful looking website setup and live on the web
on Squarespace for less than $10 a month.&lt;/p&gt;

&lt;h2&gt;Why you need to place the Experience First&lt;/h2&gt;

&lt;p&gt;One thing I&amp;#39;ve learned from my time in Business School, is that humans
&lt;a href=&quot;http://freakonomics.com/2011/06/30/the-folly-of-prediction-full-transcript/&quot;&gt;suck at predicting things&lt;/a&gt;.
Maybe we&amp;#39;re all going to be made redundant, but the ones that design the
best experiences will continue to be more relevant than ever.&lt;/p&gt;

&lt;p&gt;If creating a website or app is commoditized, so be it. After all, who&amp;#39;s going
to design and build the website builder? The fact is, designing a beautiful
experience across different mediums will never be automated, not until we
have the technology to build incredibly intelligent Sentient AIs. But by then,
we&amp;#39;d all &lt;a href=&quot;http://www.imdb.com/title/tt2209764/&quot;&gt;be in trouble&lt;/a&gt;, so I wouldn&amp;#39;t
worry about it just yet.&lt;/p&gt;

&lt;p&gt;Because it&amp;#39;s easier than ever to build a website or app, the experience matters
more than ever as the way to differentiate your product or service from the
average. When you look to hire a developer or consultancy today, I think it&amp;#39;s
important that you seek out the ones that have honed the balance between design
and engineering, and have spent time thinking about designing truly delightful
online (and offline) experiences.&lt;/p&gt;

&lt;h2&gt;Lauren is a DockYarder&lt;/h2&gt;

&lt;p&gt;I&amp;#39;ve had a very diverse and varied experience with the web â I went to design
school, did a finance degree, and started a &lt;a href=&quot;http://www.thepricegeek.com&quot;&gt;company&lt;/a&gt;.
Recently, I made the exhausting move from halfway across the world in Australia
to join DockYard, because we truly care about the entire experience. I&amp;#39;m very
proud to be able to call DY my new home.&lt;/p&gt;

&lt;p&gt;This is my first post on Reefpoints â I hope you&amp;#39;ve enjoyed reading! If you&amp;#39;d
like to read more of my writing, you can find more on my
&lt;a href=&quot;http://www.medium.com/@sugarpirate&quot;&gt;Medium&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Special mention to &lt;a href=&quot;https://twitter.com/nffrenchie&quot;&gt;@nfFrenchie&lt;/a&gt; and everyone
else who helped review this post.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Elixir: Come for the syntax, stay for everything else</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/04/08/elixir-come-for-the-syntax-stay-for-everything-else" />
    <id>https://dockyard.com/blog/2015/04/08/elixir-come-for-the-syntax-stay-for-everything-else</id>
    <category term="elixir" label="Elixir"/>
    <published>2015-04-08 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I have been programming for over 20 years now. I started with Basic,
found my way to C++, and spent two years writing Assembly (MASM). Then I
found Ruby. Ruby completely changed everything for me. I loved Ruby. I
loved Ruby for a reason that many &amp;quot;elite&amp;quot; programmers tend to dismiss:
the syntax.&lt;/p&gt;

&lt;p&gt;You see, syntax is very important to me. Call it what you will,
bikeshedding, OCD, stupidity. I care about syntax. It matters to me, and
with Ruby I found a community that shared my thoughts.&lt;/p&gt;

&lt;p&gt;When Go and Rust came along I was disappointed. Clearly these two
languages were superior in performance (and in many other areas) but were a syntactic step back
from Ruby. What was their reason? Clearly Ruby, and even Python, have
proven that the masses are attracted by clear and readable syntax. New
languages should take the best of what is currently available and
improve upon them. Go seems to target the C/C++ audience, whereas Rust
seems to attract JavaScript developers. So I guess this becomes a matter
of perspective and opinion.&lt;/p&gt;

&lt;p&gt;Elixir is different. I put Elixir up there with Go and Rust as part of
the three new languages that will define the next decade of backend
software development. With Elixir I found a language that embraced
Ruby-like syntax, but also gave me much more.&lt;/p&gt;

&lt;p&gt;The syntax is only skin deep, but this is part of allure of Elixir. It
is my foot in the door. When I first saw Elixir code I thought to myself
&amp;quot;OK, this is something I can wrap my head around&amp;quot;.&lt;/p&gt;

&lt;p&gt;I think a lot of Ruby developers will find their way to Elixir. It seems
that many were attracted to Go but I suspect when they start to explore
what the Elixir language has to offer they&amp;#39;ll see the benefits.&lt;/p&gt;

&lt;p&gt;But a language needs more than just a hook, there has to be a compelling
reason to stay. For me that was Functional Programming.&lt;/p&gt;

&lt;p&gt;It seems that Functional Programming is making a come back. Every day
there is a new blog article on why you should start writing Functional
code. Let&amp;#39;s break this down into a few points:&lt;/p&gt;

&lt;h2&gt;1. Scalability&lt;/h2&gt;

&lt;p&gt;This is an Erlang trait. Elixir apps will attempt to make the best use
of all the cores in your CPU as possible. Compared to Ruby this is a big
deal. We don&amp;#39;t have to write anything special, the Erlang VM (BEAM) just
handles this for us automatically. This means we are efficiently using
our hardware. This type of approach didn&amp;#39;t make a lot of sense a few
years ago, multi-core CPUs were expensive. Now they&amp;#39;re cheap and Elixir
benefits.&lt;/p&gt;

&lt;h2&gt;2. Memory&lt;/h2&gt;

&lt;p&gt;Elixir programs are meant to be broken into many different processes.
The garbage collection strategy being used isn&amp;#39;t revolutionary but
because we are dealing with &lt;strong&gt;many&lt;/strong&gt; runtimes instead of just one the
impact on GC is negligible. In addition, you can picture how short-lived
processes might be the equivalent of objects in an OOP lanuage. We pass
messages into the process and get back a value. Each process manages its
own memory, if the process is short-lived enough GC is never even run
and the process is destroyed after it has completed its job. As opposed
to Ruby where everything lives in one world and if you stop using the
object it will get GC&amp;#39;d eventually impacting performance.&lt;/p&gt;

&lt;h2&gt;3. Immutability&lt;/h2&gt;

&lt;p&gt;Immutability got a bad rap when memory was expensive. Why would we write
applications in such a way so as to waste memory by having variables
whose values couldn&amp;#39;t be mutated? Memory is now super cheap, and this is
not much of a concern. With this in mind we can evaluate immutability
within the context it was originally meant: to ensure state. When we
talk about parallel processing the state of a process becomes very
important. If we are expecting &lt;code&gt;X&lt;/code&gt; to always be a specific value but we
are writing in a language where &lt;code&gt;X&lt;/code&gt; can change this can lead to
problems.&lt;/p&gt;

&lt;h2&gt;4. Fault Tolerance&lt;/h2&gt;

&lt;p&gt;This one really impressed me when I started to dig into it. You may have
heard that Erlang was invented for telephony. How often do you get a
message from your phone company saying &amp;quot;we&amp;#39;re updating our systems so
you won&amp;#39;t get a call for a while&amp;quot;. This is the level of uptime that is
achievable with Elixir. Hot code swapping is another very cool feature.
Think &lt;strong&gt;real&lt;/strong&gt; Zero Downtime Deploys.&lt;/p&gt;

&lt;h2&gt;5. Community&lt;/h2&gt;

&lt;p&gt;This one is more personal to me. I&amp;#39;m attracted to technology that is not
centralized into one company. Go and Rust are very much just Google and
Mozilla technologies. Those languages will always be at the whim of
their corporate masters, wheras a language like Elixir that is not tied
to any one company feels like it has a more democratic process behind
its development. Let many companies develop use-cases and improve the
language. (I realize that Erlang falls into this category, but Erlang is
pretty much set in stone at this point)&lt;/p&gt;

&lt;p&gt;The community around Elixir also feels very much like the Ruby community
did early on. I said the same thing about the Ember.js community. I
guess I&amp;#39;m just chasing that Ruby dragon, trying to catch that high
again.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;We&amp;#39;ve been exploring Elixir heavily over the past few months. The more I
dig into the language the more I love it. We&amp;#39;re going to bet pretty
heavily on Elixir and if you are a Ruby developer looking for a change
in pace I highly suggest you check it out. The best place to start is
with &lt;a href=&quot;https://pragprog.com/book/elixir/programming-elixir&quot;&gt;Dave Thomas&amp;#39;
Book&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Helping Our Engineers</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/31/helping-our-engineers" />
    <id>https://dockyard.com/blog/2015/03/31/helping-our-engineers</id>
    <category term="html" label="Html"/>
    <published>2015-03-31 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Amanda Cheung</name></author>
    <summary>Writing Pseudo-Code as UX Developers</summary>
    <content type="html">&lt;h2&gt;Writing Pseudo-Code as UX Developers&lt;/h2&gt;

&lt;p&gt;As a team, we are always trying to improve our process at DockYard to
make things easier for one another. Iâm part of the UX development team, which
takes care of the HTML and CSS/Sass for our projects.
One thing we have found to be helpful to our Ember/back-end engineers is pseudo-coding
where loops and conditionals should go in our templates. It only takes a basic understanding of
&lt;a href=&quot;https://pine.fm/LearnToProgram/chap_06.html&quot;&gt;flow control&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When we are in the development phase of a project, UX development usually tries to
complete HTML first. That way UX dev and engineering can work in
parallel without completion times depending on each other. What can we
do to make this process smoother? Below are two code examples of what an engineer may see given these mockups.
&lt;img alt=&quot;Has no followers&quot;
src=&quot;https://dl.dropboxusercontent.com/u/38675407/followers--no-followers.png&quot;&gt;
&lt;img alt=&quot;Followers shows interests&quot;
src=&quot;https://dl.dropboxusercontent.com/u/38675407/followers--with-interests.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;Unorganized comments:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;{{! at the beginning the user will not have any followers so show this}}&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follows-wrap&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follows--is-empty&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;You donât have any followers.&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;{{! when a user has followers show this block and not the block above}}&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follows-wrap&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follows&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__image&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Alfred H.&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;h3&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__interests__heading&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Follows for:&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;comment&quot;&gt;{{! must be following for at least one interest to have a follower. when the follower is only following for one interest will not have the part that says 2 others or span below that}}&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__interest&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Tennis &lt;span class=&quot;entity&quot;&gt;&amp;amp;amp;&lt;/span&gt; Racquet Sports,
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__interest--other&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;2 others&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__modal__interests&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__modal__interest&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Photography&lt;span class=&quot;tag&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__modal__interest&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Soccer&lt;span class=&quot;tag&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Pseudo-code comments:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follows-wrap&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;{{! if user has followers}}&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follows&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;comment&quot;&gt;{{! each follower / following}}&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__image&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Alfred H.&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;h3&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__interests__heading&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Follows for:&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__interest&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
            Tennis &lt;span class=&quot;entity&quot;&gt;&amp;amp;amp;&lt;/span&gt; Racquet Sports
            &lt;span class=&quot;comment&quot;&gt;{{! if following for more than one interest}}&lt;/span&gt;
              ,
              &lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__interest--other&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;2 others&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;tag&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__modal__interests&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;tag&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__modal__interest&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Photography&lt;span class=&quot;tag&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;tag&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follow__modal__interest&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Soccer&lt;span class=&quot;tag&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;tag&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;comment&quot;&gt;{{!end if}}&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;comment&quot;&gt;{{! end each}}&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;{{! else}}&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;follows--is-empty&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;You donât have any followers.&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;{{! end if}}&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The unorganized way can get out of hand with complex applications. The
pseudo-code method turns out to be slightly more work for UX developers,
but it saves our engineers a lot of time and confusion. Being able to break
things down into simple if/else statements or each loops has been much more efficient.
No more reading paragraphs of whatâs supposed to go where and when, or
re-organizing the template!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Pluralize Your Word(s) With ember-pluralize</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/27/pluralize-your-words-with-ember-pluralize" />
    <id>https://dockyard.com/blog/2015/03/27/pluralize-your-words-with-ember-pluralize</id>
    <category term="ember" label="Ember.js"/><category term="addon" label="Addon"/><category term="javascript" label="JavaScript"/>
    <published>2015-03-27 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Romina Vargas</name></author>
    <summary>Introducing a pluralizing addon based on a given count.</summary>
    <content type="html">&lt;p&gt;Do you ever find yourself repeating identical pieces of code throughout
different projects? If so, that&amp;#39;s the perfect indicator for an addon
opportunity. Ember Addons allow you to quickly integrate sharable code
into different projects, without copy and pasting, via one simple command:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;  ember install:addon addon-name
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On some of our most recent projects, we kept finding the need to
pluralize words based on &lt;em&gt;how many&lt;/em&gt; of each item we had. Also, since
our data is dynamic and constantly changing, the pluralization of a
word should remain in sync with our fluctuating data. And so
&lt;a href=&quot;https://github.com/rsocci/ember-pluralize&quot;&gt;&lt;code&gt;ember-pluralize&lt;/code&gt;&lt;/a&gt; was born.&lt;/p&gt;

&lt;p&gt;After a quick &lt;code&gt;ember install:addon ember-pluralize&lt;/code&gt;, using the addon
is a piece of cake.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s suppose we have a model like so:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  &lt;span class=&quot;function&quot;&gt;model&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Ember.A([
      Ember.Object.create({ &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Cartman&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;cheesyPoofs&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;20&lt;/span&gt; }),
      Ember.Object.create({ &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Stan&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;cheesyPoofs&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt; }),
      Ember.Object.create({ &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Kyle&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;cheesyPoofs&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; }),
      Ember.Object.create({ &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Kenny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;cheesyPoofs&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt; })
    ]);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we want to output how many Cheesy Poofs each person has. This addon
provides a helper that allows us to do the following in our template:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#each model as |person|}}
  {{person.name}} has {{h-pluralize person.cheesyPoofs &amp;quot;Cheesy Poof&amp;quot;}}
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;which will output&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;// Cartman has 20 Cheesy Poofs
// Stan has 5 Cheesy Poofs
// Kyle has 1 Cheesy Poof
// Kenny has 0 Cheesy Poofs
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And now, as they each start throwing back some Cheesy Poofs, the counts
will start to update, as well as the word &amp;quot;Cheesy Poof&amp;quot;, according to
how many are remaining. Alternatively, if you don&amp;#39;t need to display the
actual number, passing in &lt;code&gt;omitCount=true&lt;/code&gt; as the third parameter will
exclude it from the output:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#each model as |person|}}
  {{person.name}}&#39;s {{h-pluralize person.cheesyPoofs &amp;quot;Cheesy Poof&amp;quot; omitCount=true}}
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;// Cartman&#39;s Cheesy Poofs
// Stan&#39;s Cheesy Poofs
// Kyle&#39;s Cheesy Poof
// Kenny&#39;s Cheesy Poofs
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note: If you&amp;#39;re using Ember Data, you will be provided with a built in pluralize
helper through the &lt;a href=&quot;https://github.com/stefanpenner/ember-inflector&quot;&gt;Ember Inflector&lt;/a&gt;
library. The helper is registered for availability in the template; the
functionality is similar, but given that it takes up to two arguments
(the count and the word), you&amp;#39;re not able to solely display the pluralized
word based on a given a count.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;d like to see more on the addon, it can be found on
&lt;a href=&quot;https://github.com/rsocci/ember-pluralize&quot;&gt;GitHub&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Bringing Ember to the Desktop with NW.js</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/26/bringing-ember-to-the-desktop-part" />
    <id>https://dockyard.com/blog/2015/03/26/bringing-ember-to-the-desktop-part</id>
    <category term="ember" label="Ember.js"/>
    <published>2015-03-26 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Estelle DeBlois</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;One of our recent client projects at DockYard had us go in a totally new
direction in terms of technology stack. We needed to build a desktop
application that could communicate with some Arduino devices via
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/WebSockets&quot;&gt;WebSockets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let me first put this out there: I love building for the web. The mere
thought of developing native desktop applications always makes me cringe
a little, though I admit, I haven&amp;#39;t done much in that arena since those
&lt;a href=&quot;http://en.wikipedia.org/wiki/Swing_%28Java%29&quot;&gt;Java Swing&lt;/a&gt; days from forever ago.
Nevertheless, you may find yourself at some point needing to build for the desktop.
Thankfully, you don&amp;#39;t have to put your fuzzy little Tomster away.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/nwjs/nw.js&quot;&gt;NW.js&lt;/a&gt;, formerly known as Node WebKit, is a runtime
built on top of Chromium and Node/IO.js that lets you develop native applications
using the web technologies that you love. You can essentially build an Ember app, and
also invoke Node modules all within the browser, then package it up as
a Mac OS X application or Windows &lt;code&gt;exe&lt;/code&gt; file when you&amp;#39;re ready to distribute.&lt;/p&gt;

&lt;h2&gt;Demo&lt;/h2&gt;

&lt;p&gt;Here&amp;#39;s a screenshot from a NW.js app built with Ember for demonstration
purposes:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cloud.githubusercontent.com/assets/1691398/6768192/536a6fde-d033-11e4-9375-e2f506c1c8c7.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#39;s a simple GitHub-flavored Markdown Editor that lets you create and preview
Markdown documents, and save them to disk.&lt;/p&gt;

&lt;p&gt;You can try it for yourself. Just download the application from the
following links for your platform, unzip, then double-click on &lt;code&gt;Markdown
Editor.app&lt;/code&gt; (Mac) or &lt;code&gt;Markdown Editor.exe&lt;/code&gt; (Windows).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mac OS X: &lt;a href=&quot;https://s3.amazonaws.com/dockyard-general/ember-nw-demo/markdown-editor-osx64.zip&quot;&gt;markdown-editor-osx64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Windows:
&lt;a href=&quot;https://s3.amazonaws.com/dockyard-general/ember-nw-demo/markdown-editor-win64.zip&quot;&gt;markdown-editor-win64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/brzpegasus/ember-nw-markdown&quot;&gt;Source code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a touch of user friendliness, the app even ships with your favorite
mascot:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mac:&lt;/em&gt;
&lt;img alt=&quot;Mac Icon&quot; src=&quot;https://cloud.githubusercontent.com/assets/1691398/6853610/9ee8c52c-d3c2-11e4-971a-3472bfd35609.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em style=&quot;display: block;&quot;&gt;Windows:&lt;/em&gt;
&lt;img alt=&quot;Windows Icon&quot; src=&quot;https://cloud.githubusercontent.com/assets/1691398/6853614/a32becc2-d3c2-11e4-9ed4-83d645825f4b.png&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;The main entry point to a NW.js application is an HTML page that you
specify in your project&amp;#39;s &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight json &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;my-app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;dist/index.html&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;On startup, NW.js will launch a new Chromium browser window,
then set the location to that starting page:
&lt;code&gt;file:///Users/brzpegasus/projects/my-app/dist/index.html#/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This does require that you set your &lt;code&gt;Ember.Router&lt;/code&gt;
&lt;a href=&quot;http://emberjs.com/api/classes/Ember.Location.html&quot;&gt;location type&lt;/a&gt; to &lt;code&gt;hash&lt;/code&gt;. In Ember CLI,
this is a simple tweak to your &lt;code&gt;config/environment.js&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// config/environment.js&lt;/span&gt;
modules.&lt;span class=&quot;function&quot;&gt;exports&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(environment) {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; ENV = {
    &lt;span class=&quot;key&quot;&gt;locationType&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;comment&quot;&gt;// Change this from &#39;auto&#39; to &#39;hash&#39;&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// ...&lt;/span&gt;
  };
};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;From there on, you should feel quite at home and ready to develop your Ember app.&lt;/p&gt;

&lt;p&gt;Or maybe not quite yet.&lt;/p&gt;

&lt;h2&gt;A Bit About NW.js&lt;/h2&gt;

&lt;p&gt;NW.js tweaks Chromium and Node in order to
&lt;a href=&quot;https://github.com/nwjs/nw.js/wiki/How-node.js-is-integrated-with-chromium&quot;&gt;integrate&lt;/a&gt;
the two worlds and make it possible for you to call Node modules from the client:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;console.log(location.href);   &lt;span class=&quot;comment&quot;&gt;// Yup, we&#39;re in browser land&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; fs = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);       &lt;span class=&quot;comment&quot;&gt;// Call core Node modules&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; async = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// Or even third-party modules!&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you&amp;#39;re used to Node and CommonJS, this &lt;code&gt;require&lt;/code&gt; function should look very
familiar, but it isn&amp;#39;t exactly the same. Here&amp;#39;s what it does:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;require&lt;/span&gt;(name) {
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (name == &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;nw.gui&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; nwDispatcher.requireNwGui();
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; global.require(name);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;So if you were to call &lt;code&gt;require(&amp;#39;nw.gui&amp;#39;)&lt;/code&gt;, you would get access to the
&lt;a href=&quot;https://github.com/nwjs/nw.js/wiki/Native-UI-API-Manual&quot;&gt;Native UI Library&lt;/a&gt;
to do things like manipulating the window frame, adding menus, keyboard shortcuts, etc.
Otherwise, the function ends up calling &lt;code&gt;global.require&lt;/code&gt; to import Node modules.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;global&lt;/code&gt; is Node&amp;#39;s global namespace object. You can use it to retrieve
other global objects besides &lt;code&gt;require&lt;/code&gt;, such as &lt;code&gt;global.process&lt;/code&gt;.
However, many of them are made available directly on the &lt;code&gt;window&lt;/code&gt; object, so you can
reference them without prefix, just as you would in Node:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;console.log(window.process === global.process) &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; true&lt;/span&gt;
console.log(process.env.USER) &lt;span class=&quot;comment&quot;&gt;// &amp;quot;brzpegasus&amp;quot;&lt;/span&gt;
console.log(process.platform) &lt;span class=&quot;comment&quot;&gt;// &amp;quot;darwin&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Naming Conflicts&lt;/h2&gt;

&lt;p&gt;Modules written with ES2015 (&lt;a href=&quot;https://esdiscuss.org/topic/javascript-2015#content-3&quot;&gt;previously, ES6&lt;/a&gt;)
syntax in your Ember app get transpiled into
AMD for today&amp;#39;s browsers. This is problematic because AMD also specifies a
&lt;code&gt;require&lt;/code&gt; function for loading modules. In Ember CLI, this is implemented via
&lt;a href=&quot;https://github.com/ember-cli/loader.js&quot;&gt;ember-cli/loader.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By the time the app is done loading, any functionality that depends on
the native UI library or Node modules will break as the &lt;code&gt;require&lt;/code&gt;
function would have been redefined.&lt;/p&gt;

&lt;p&gt;You can get around this by saving a reference to Node&amp;#39;s &lt;code&gt;require&lt;/code&gt; before loading
any script. Once all scripts are loaded and executed, redefine &lt;code&gt;require&lt;/code&gt;
to work with both module systems. This is necessary as certain operations
will not work with the alias:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Before loading any script&lt;/span&gt;
window.requireNode = require;

&lt;span class=&quot;comment&quot;&gt;// After all scripts are loaded&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; requireAMD = require;

window.&lt;span class=&quot;function&quot;&gt;require&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;try&lt;/span&gt; {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; requireAMD.apply(&lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
  } &lt;span class=&quot;keyword&quot;&gt;catch&lt;/span&gt; (error) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; requireNode.apply(&lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
  }
};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;An Addon For All Your NW.js Needs&lt;/h2&gt;

&lt;p&gt;I&amp;#39;ve recently released an Ember CLI addon to help make this process
easier. Simply install &lt;a href=&quot;https://github.com/brzpegasus/ember-cli-node-webkit&quot;&gt;ember-cli-node-webkit&lt;/a&gt;,
then start coding right away. All the configuration will be taken care
of for you, so no need to worry about &lt;code&gt;require&lt;/code&gt; naming conflicts.&lt;/p&gt;

&lt;p&gt;The addon can build your project, watch for changes, and reload the page in NW.js
during development. And when you&amp;#39;re ready to distribute, packaging is just
one command away. The packaging is a wrapper around the excellent
&lt;a href=&quot;https://github.com/mllrsohn/node-webkit-builder&quot;&gt;node-webkit-builder&lt;/a&gt;
but the configuration is done automatically based on the addon&amp;#39;s
understanding of your app structure.&lt;/p&gt;

&lt;p&gt;I will not spend time talking about the addon in this blog post, but I
invite you to check out the &lt;a href=&quot;https://github.com/brzpegasus/ember-cli-node-webkit/blob/master/README.md&quot;&gt;README&lt;/a&gt;
to get familiar with all the options that are at your disposal.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;When we first set out to build a desktop app for a client project,
documentation on how to integrate NW.js with Ember was scarce. Even more
scarce was documentation on how to integrate it with Ember CLI. I hope
this post and this addon will provide some guidance to others down the
road.&lt;/p&gt;

&lt;p&gt;I&amp;#39;d love to share some code samples and discuss patterns you can adopt
to make your NW.js app more manageable and testable, but they&amp;#39;d be too
dense for this introductory blog post. However, you&amp;#39;ll be hearing more from me
on this topic in the future!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Testing when your frontend and backend are separated</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/25/testing-when-your-frontend-and-backend-are-separated" />
    <id>https://dockyard.com/blog/2015/03/25/testing-when-your-frontend-and-backend-are-separated</id>
    <category term="ember" label="Ember.js"/><category term="testing" label="Testing"/>
    <published>2015-03-25 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>How can you run full integration tests when using separate repos?</summary>
    <content type="html">&lt;p&gt;The last project I worked on was an Ember app that had a Rails backend that was
deployed on Heroku. We had this application as a single repository, where there
were two folders at the root, &lt;code&gt;frontend&lt;/code&gt; and &lt;code&gt;backend&lt;/code&gt;. This was somewhat easy
to test on Travis-CI; it would check out the one repository, run the Rails
tests, start the Rails server, then run the ember tests that hit the Rails
server. This ended up being a pain to deploy, as when you changed the Rails app,
you were going to redeploy the Ember app, and vice-versa.  It also presented an
issue when deploying to Heroku, as &lt;a href=&quot;https://www.youtube.com/watch?v=ceFNLdswFxs&amp;amp;t=4103&quot;&gt;we had to utilize &lt;code&gt;git subtree&lt;/code&gt; to push
the backend&lt;/a&gt;, which
contained the production assets.&lt;/p&gt;

&lt;p&gt;With the latest project I started, I&amp;#39;m keeping the backend and the Ember app
separate.  Since the apps are separate, they can be deployed independant of
each other. This made it a little bit harder to run integration tests against
the backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Side note:&lt;/strong&gt; while you can mock/stub your API in your Ember tests, it is
important to run integration tests against your backend regularly. When you
mock your API, it ends up giving you this false sense of security when it comes
to your Ember app being compatible. Your models may line up perfectly with your
mocks, but your mocks can fall out of date. To prevent this, at least when
running on your continuous integration (CI) server, you should have your Ember
app hit the backend server.&lt;/p&gt;

&lt;p&gt;To run end-to-end integration tests on Travis-CI, I added tasks to the
&lt;code&gt;.travis.yml&lt;/code&gt; file to clone the backend repository, install dependencies, and
run the server:&lt;/p&gt;
&lt;div class=&quot;highlight yml &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;key&quot;&gt;language&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;node_js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;node_js&lt;/span&gt;:
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;0.12&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;key&quot;&gt;sudo&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;cache&lt;/span&gt;:
  &lt;span class=&quot;key&quot;&gt;directories&lt;/span&gt;:
    - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;node_modules&lt;/span&gt;&lt;/span&gt;
    - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;backend&lt;/span&gt;&lt;/span&gt;
    - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;vendor/bundle&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;key&quot;&gt;before_install&lt;/span&gt;:
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;npm config set spin false&lt;/span&gt;&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;npm install -g npm@^2&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# Select the RVM version&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;rvm use 2.2.1 --install --binary --fuzzy&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# Clone the repository if isn&#39;t cloned&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[ -d backend/.git ] || git clone git@github.com:&amp;lt;backend-repo&amp;gt; backend&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;cd backend&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# Reset the repo so we can have a conflict-less pull&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;git reset --hard&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;git clean -f&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;git pull&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# Install dependencies&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bundle install --path=../vendor/bundle --jobs=3 --retry=3 --deployment&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# Run the server&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;RAILS_ENV=test ./bin/rails s &amp;amp;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# Wait for the Rails app to start&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;sleep 5&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;cd ..&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;key&quot;&gt;install&lt;/span&gt;:
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;npm install -g bower&lt;/span&gt;&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;npm install&lt;/span&gt;&lt;/span&gt;
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;bower install&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;key&quot;&gt;script&lt;/span&gt;:
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;npm test&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note that I cached both the backend and bundle directories to speed up the time
it takes to get the backend running. Since the backend is cached, we only have
to pull the new code.&lt;/p&gt;

&lt;p&gt;In this example, we have a Rails app with no database, but it would be pretty
easy to add one. The only other required step was to add an SSH private key to
the Travis settings, since you would have two separate deploy keys. That would
prevent you from cloning the backend repository from the frontend test.  There
should be nothing holding you back from performing end to end tests when you
have separate repositories!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Rubyists Guide to Ember.js Dependencies</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/24/rubyists-guide-to-ember-dependencies" />
    <id>https://dockyard.com/blog/2015/03/24/rubyists-guide-to-ember-dependencies</id>
    <category term="ruby" label="Ruby"/><category term="ember" label="Ember.js"/>
    <published>2015-03-24 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Michael Dupuis</name></author>
    <summary>A dependency management primer for Rubysist living in a Gemfile-less, Ember.js world.</summary>
    <content type="html">&lt;p&gt;At DockYard, we have a lot of Ruby on Rails experts who have adopted Ember on the frontend. One of the early hurdles a Ruby developer faces when working on an Ember.js application is dependency management. A popular mechanism for managing a Ruby applicationâs dependencies is the &lt;a href=&quot;http://bundler.io/gemfile.html&quot;&gt;Gemfile&lt;/a&gt; provided by &lt;a href=&quot;http://bundler.io/&quot;&gt;Bundler&lt;/a&gt;. Including a library is as easy as declaring it in the Gemfile and running &lt;code&gt;bundle install&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# Gemfile&lt;/span&gt;
source &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;https://rubygems.org&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;rails&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;~&amp;gt; 4.2.0&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For better or worse, there is no dominant, single package manager in JavaScript. Ember applications, and more specifically, those running &lt;a href=&quot;http://www.ember-cli.com/&quot;&gt;Ember-CLI&lt;/a&gt;, rely on two package managers: &lt;a href=&quot;http://bower.io/&quot;&gt;Bower&lt;/a&gt; for client-side libraries and &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; for server-side libraries.&lt;/p&gt;

&lt;p&gt;In this post, I&amp;#39;ll provide a basic dependency management primer for
those moving from Ruby to JavaScript.&lt;/p&gt;

&lt;h2&gt;npm&lt;/h2&gt;

&lt;p&gt;Ember-CLI uses npm to manage internal dependencies. npm resembles RubyGems, in so far as it allows you to install and manage third-party libraries, which in this case, are Node.js programs.&lt;/p&gt;

&lt;h3&gt;package.json&lt;/h3&gt;

&lt;p&gt;Libraries for npm are referred to as âpackages.â Each package has a &lt;code&gt;package.json&lt;/code&gt; file which lists the dependencies of the library itself. In this regard, the &lt;code&gt;package.json&lt;/code&gt; is analogous to a RubyGemâs &lt;code&gt;gemspec&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;.npmrc&lt;/h3&gt;

&lt;p&gt;You can configure how node packages get installed via the
&lt;a href=&quot;https://docs.npmjs.com/files/npmrc&quot;&gt;.npmrc file&lt;/a&gt;. You may have one
globally, per user (&lt;code&gt;~/.npmrc&lt;/code&gt;), or per project.&lt;/p&gt;

&lt;h3&gt;Installing dependencies&lt;/h3&gt;

&lt;p&gt;To install an npm package, run &lt;code&gt;npm install [package-name]&lt;/code&gt; from the
command line.&lt;/p&gt;

&lt;p&gt;This will either install the library and it&amp;#39;s dependencies
into your current working directory or in one of its parent directories. Here&amp;#39;s how it works: if there is a &lt;code&gt;node_modules/&lt;/code&gt; or &lt;code&gt;package.json&lt;/code&gt; in any directory above the current working directory, packages will be installed into that directory. Otherwise, calling &lt;code&gt;npm install [package-name]&lt;/code&gt; creates a &lt;code&gt;node_modules/&lt;/code&gt; directory in your current working directory and installs the packages there.&lt;/p&gt;

&lt;p&gt;This is a slightly different mental model for Rubyists who are not used to installing gems on a per project basis; gems are generally installed into version-specific Ruby directories with the more popular version managers like &lt;a href=&quot;https://github.com/sstephenson/rbenv&quot;&gt;rbenv&lt;/a&gt; or &lt;a href=&quot;https://rvm.io/&quot;&gt;RVM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Itâs also possible to install packages globally using the &lt;code&gt;--global&lt;/code&gt; flag when installing. This installs the package in your &lt;code&gt;usr/local/lib/&lt;/code&gt; directory by default. These packages typically contain executable files and are used via the command line (such as Ember-CLI).&lt;/p&gt;

&lt;p&gt;Your dependencies will likely have dependencies. These get installed within a &lt;code&gt;node_modules/&lt;/code&gt; directory in the given package. It&amp;#39;s a little strange the first time you navigate into a &lt;code&gt;node_modules/package-name/&lt;/code&gt; only to find another &lt;code&gt;node_modules/&lt;/code&gt; directory, but that&amp;#39;s what that is. Youâll notice a &lt;code&gt;node_modules/&lt;/code&gt; directory for dependencies of global packages as well if you look in the &lt;code&gt;usr/local/lib/&lt;/code&gt; directory where global packages live.&lt;/p&gt;

&lt;p&gt;One last thing to note regarding npm installations: npm caches the
libraries you pull down to prevent you from having to download
libraries that are already on your system. You&amp;#39;ll find that cache:
&lt;code&gt;~/.npm/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Bower&lt;/h2&gt;

&lt;p&gt;While you&amp;#39;ll use npm to manage your server-side Node.js dependencies, youâll use Bower for managing front-end assets, such as JavaScript, HTML, CSS, image, and font files.&lt;/p&gt;

&lt;h3&gt;.bowerrc&lt;/h3&gt;

&lt;p&gt;Bower itself is an npm package. Its libraries are referred to as âcomponentsâ and the end user can configure their installations via a &lt;code&gt;.bowerrc&lt;/code&gt; file. This file specifies where dependent components will be installed, the URL where the component will be registered (its registry), and the JSON file used to define the component (&lt;code&gt;bower.json&lt;/code&gt; by default) among other things.&lt;/p&gt;

&lt;h3&gt;bower.json&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;http://bower.io/docs/creating-packages/#bowerjson&quot;&gt;&lt;code&gt;bower.json&lt;/code&gt;&lt;/a&gt; file resembles the &lt;a href=&quot;http://guides.rubygems.org/specification-reference/&quot;&gt;gemspec&lt;/a&gt; file you find in Ruby gems. It contains the library metadata, such as the name, version, dependencies, and development dependencies for the library.&lt;/p&gt;

&lt;p&gt;As we mentioned, components can be searched for via registries. The registry matches the name of a component with the endpoint at which itâs hosted. &lt;a href=&quot;http://bower.io/search/&quot;&gt;Bower.io/search&lt;/a&gt; closely resembles &lt;a href=&quot;https://rubygems.org/gems&quot;&gt;rubygems.org&lt;/a&gt; in this way.&lt;/p&gt;

&lt;h3&gt;Installing dependencies&lt;/h3&gt;

&lt;p&gt;When you install a Bower component via &lt;code&gt;bower install [component_name]&lt;/code&gt;, the repository will be cached locally to expedite any future installations of the component. In case youâre curious, the bower cache location is: &lt;code&gt;~/.cache/bower/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unlike npm, Bower components are installed &amp;quot;flat&amp;quot; as opposed to in a hierarchical manner; all of your project&amp;#39;s components (and their dependencies) will be installed into &lt;code&gt;bower_components/&lt;/code&gt; directory, by default. For example, if one of your components is dependent on the &lt;code&gt;underscore.js&lt;/code&gt; library, both will sit side-by-side in the &lt;code&gt;bower_components/&lt;/code&gt; directory (remember, with npm, dependencies of dependencies are continually nested in their parent&amp;#39;s directory within a &lt;code&gt;node_modules/&lt;/code&gt; directory).&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Here&amp;#39;s a quick wrap-up of the analogous files between Ruby and the JS
package managers we discussed:&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Ruby&lt;/th&gt;
&lt;th&gt;JS (npm, server-side)&lt;/th&gt;
&lt;th&gt;JS (Bower, client-side)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Term for external library&lt;/td&gt;
&lt;td&gt;&amp;quot;Gem&amp;quot;&lt;/td&gt;
&lt;td&gt;&amp;quot;Package&amp;quot;&lt;/td&gt;
&lt;td&gt;&amp;quot;Component&amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End-user configuration file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.gemrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.npmrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.bowerrc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-library configuration file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*.gemspec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bower.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.gem/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.npm/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/.cache/bower/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;As ES2015 (formerly known as &amp;quot;ES6&amp;quot;) becomes more prevalent and JavaScript code becomes more
modular and better for passing around, dependency management grows in
importance. Hopefully this quick primer will clear up some
confusion Rubysists have as they transition from working with the
Gemfile to working with the package managers JavaScript offers.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Beginnerâs mentality</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/23/beginner-mentality" />
    <id>https://dockyard.com/blog/2015/03/23/beginner-mentality</id>
    <category term="design" label="Design"/><category term="observations" label="Observations"/>
    <published>2015-03-23 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>A fresh perspective can help an expert find and address their blind spots.</summary>
    <content type="html">&lt;p&gt;Many people consider us UX or Web experts, and experts are clearly the best people for the job. But we know we have a significant blind spot - our extensive knowledge of the system makes us less likely to see the potential problems a novice might encounter. Anyone who is very familiar with a system, a discipline, or a product has put some distance between them and their beginning level challenges that cause them to develop an &lt;a href=&quot;http://c4ed.lib.kmutt.ac.th/sites/default/files/HowLearningWorks-Ambrose.pdf&quot;&gt;expert blind spot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am sure you are familiar with this situation: youâre invited (or invite yourself) to an event at a university campus. You arrive a bit earlier than you needed, so you can orient yourself in the unfamiliar space. The map on your phone is only accurate to the nearest block, so you get a campus map and try to find room 41-B in the Humanities building named after someone important. You feel stupid.&lt;/p&gt;

&lt;p&gt;This is what campus maps often look like:
&lt;img src=&quot;http://imgur.com/Aulbb3t.jpg&quot; alt=&quot;An old map showing a campus as an island surrounded by unknown waters&quot;&gt;&lt;/p&gt;

&lt;p&gt;The reason most outsiders find campus maps confusing and difficult to use is the shift in the frame of reference.&lt;/p&gt;

&lt;p&gt;For someone who lives or works on campus, the frame of reference is relative to the borders and shape of the universe that is the university (or corporate, or hospital) campus. They might consider their office to be âin the far North cornerâ relative to the outline of the campus on a map. Or, they might think of themselves as âright in the middle of the Art Departmentâ. The Art Department here is amorphous: itâs something that may either span two city blocks, or half of a floor in a physical building.&lt;/p&gt;

&lt;p&gt;For an outsider, the frame of reference is still the surrounding landscape. They may not know precisely when they entered the school campus (there is no painted border on the ground) or that they are in its top left corner. The âyou are hereâ marker on the campus map helps, but it still takes a while to adjust to the landmarks differentiated by department, not by road or city block. To find a building, they are forced to adapt to a new system of coordinates.&lt;/p&gt;

&lt;h2&gt;Work with an outsider&lt;/h2&gt;

&lt;p&gt;I often see this situation reflected in the websites of large institutions. When someone very close to an institution thinks of how their web presence may be organized or used, they inevitably do so with the influence of all the expertise they have. They canât help it - they âliveâ inside the campus, and they are good at what they do.&lt;/p&gt;

&lt;p&gt;There are many examples of this kind of insider thinking: organizing content by internal structure (instead of user need), breaking up a university website into Athletics, Academics, and Arts (which one contains the event I want to attend?) or assuming that a typical user has even a basic understanding of specialized terminology and concepts.&lt;/p&gt;

&lt;p&gt;This is by no means a treaty against specialized knowledge and perspective. The insider knowledge of an industry expert makes a product good, their know-how makes it work. But the outside perspective of a novice-expert truly helps make a product findable and usable.&lt;/p&gt;

&lt;p&gt;To attract new customers or visitors, a product needs to make sense to someone unfamiliar with it in their own broader frame of reference. To ask the right questions, to establish user goals and needs, and to judge the effectiveness and clarity of a product, we need both the insider and the outsider perspective.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Tips for writing Ember Addons</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/22/tips-for-writing-ember-addons" />
    <id>https://dockyard.com/blog/2015/03/22/tips-for-writing-ember-addons</id>
    <category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/>
    <published>2015-03-22 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;After having published many Ember addons I have started to develop my
own sense of &amp;quot;Best Practices&amp;quot; and I&amp;#39;d like to share those with you:&lt;/p&gt;

&lt;h2&gt;1. Keep it minimal, don&amp;#39;t include stylesheets&lt;/h2&gt;

&lt;p&gt;I see quite a few addons out there that include their own look &amp;amp; feel by
including sytlesheets. I actually think this is a bad idea. &lt;em&gt;Keep in
mind, every line of code you put into your addon will end up in the
final footprint of the apps consuming it&lt;/em&gt;. This means if you are
including stylesheets those will end up in &lt;code&gt;vendor.css&lt;/code&gt;. The odds are
that whatever styles you decide look good, someone else might not.
They&amp;#39;ll waste even more space by including their own overrides. This is
wasteful.&lt;/p&gt;

&lt;p&gt;Instead, you should &lt;em&gt;keep it minimal&lt;/em&gt;. See
&lt;a href=&quot;https://github.com/dockyard/ember-admin&quot;&gt;ember-admin&lt;/a&gt;. I intentionally
did not style the addon so it is left as minimal as possible. If you
want to show off a styled version of the addon, you can either include
styles in the dummy app&amp;#39;s styles for the addon&amp;#39;s test dummy. Allow
people to run the addon&amp;#39;s server locally and view what could be. Or, you
can include an addon wrapper library that depends upon your addon. This
wrapper can include default styles that consumers may choose not to
alter. For example,
&lt;a href=&quot;https://github.com/dockyard/ember-admin-bootstrap&quot;&gt;ember-admin-bootstrap&lt;/a&gt;
styles ember-admin with Twitter Bootstrap. If this is good enough for
you then you just install this library and it pulls in ember-admin but
gives you some nice styling that you don&amp;#39;t have to spend time doing.&lt;/p&gt;

&lt;h2&gt;2. Allow for overrides&lt;/h2&gt;

&lt;p&gt;I believe strongly in composable addons. A consumer should have the
ability to easily extend your addon to do whatever they want. This means
organizing your code a certain way. To provide this you should put all
of your business logic into &lt;code&gt;addon/&lt;/code&gt; and then include wrapper classes in
&lt;code&gt;app/&lt;/code&gt; that just &lt;code&gt;import&lt;/code&gt; then &lt;code&gt;export&lt;/code&gt; the extended class. For example:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// addon/components/foo-bar.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Component.extend({
  &lt;span class=&quot;comment&quot;&gt;// business logic&lt;/span&gt;
});

&lt;span class=&quot;comment&quot;&gt;// app/components/foo-bar.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; FooBar from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;my-addon/components/foo-bar&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; FooBar;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;These light wrapper classes &lt;strong&gt;should not&lt;/strong&gt; include any business logic.
Again, they simply &lt;code&gt;import&lt;/code&gt; then &lt;code&gt;export&lt;/code&gt; the extended class. This gives
consumers the option of overriding this in their own
&lt;code&gt;app/components/foo-bar.js&lt;/code&gt; file to extend and add customization.&lt;/p&gt;

&lt;h2&gt;3. Turn off Prototype Extensions&lt;/h2&gt;

&lt;p&gt;Currently ember-cli will not generate an addon project with Prototype
Extensions turn off. However, &lt;a href=&quot;https://github.com/ember-cli/ember-cli/issues/3443&quot;&gt;I have requested this be the
default&lt;/a&gt;. Turning
off Prototype Extensions will cause the following syntax to fail in
your addon&amp;#39;s test suite:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;function&quot;&gt;foo&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;comment&quot;&gt;// whatever&lt;/span&gt;
}.property(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There are several syntax shortcuts that Ember injects into the base
Types. Arrays have quite a bit. Turning off Prototype Extensions will
force you to write the above code as:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;foo: Ember.computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;comment&quot;&gt;// whatever&lt;/span&gt;
})
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And this will play nice with consumer applications that must run with
the Prototype Extensions turned off.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/emberjs/ember.js/issues/10590&quot;&gt;It should be noted that Ember 1.10 has a bug where turning off Prototype
Extensions causes Ember itself to
fail&lt;/a&gt;. This should be
fixed in 1.11 (&lt;strong&gt;Update: This has been addressed in &lt;a href=&quot;https://github.com/emberjs/ember.js/pull/10697&quot;&gt;Ember&lt;/a&gt;.&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Avoiding Prototype Extensions can be difficult. I plan on writing a
future blog post to outline certain strategies to duplicate the behavior
that you miss out on without Prototype Extensions.&lt;/p&gt;

&lt;p&gt;To turn off Prototype Extensions you&amp;#39;ll need to install the &lt;code&gt;ember-disable-prototype-extensions&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;npm install --save-dev ember-disable-prototype-extensions
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;See
&lt;a href=&quot;https://github.com/dockyard/ember-validations/pull/270&quot;&gt;ember-validations&lt;/a&gt;
for an example.&lt;/p&gt;

&lt;h2&gt;4. Test your addon&lt;/h2&gt;

&lt;p&gt;This one should go without saying but I have seen &lt;em&gt;way&lt;/em&gt; too many addons
out there that are untested (the generated tests don&amp;#39;t count). Please
keep in mind that there are people building products that might consume
your work. Untested code is just one more thing that could go wrong in
someone&amp;#39;s app. If unit testing the code is too difficult, at the very
least write integration tests against the dummy application to ensure
the happy paths.&lt;/p&gt;

&lt;h2&gt;5. Depend on other addons&lt;/h2&gt;

&lt;p&gt;You may not know this but addons can depend upon addons. Rather than
recreating behavior per-addon it would be best to extract out common
behavior to its own dependency. For example,
&lt;a href=&quot;https://github.com/dockyard/ember-data-route&quot;&gt;ember-data-route&lt;/a&gt; and
&lt;a href=&quot;https://github.com/dockyard/ember-cli-async-button&quot;&gt;ember-cli-async-button&lt;/a&gt;
are both being used in
&lt;a href=&quot;https://github.com/dockyard/ember-admin/blob/master/package.json#L21-L23&quot;&gt;ember-admin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use an addon as a dependency it &lt;em&gt;must&lt;/em&gt; be put into the &lt;code&gt;dependencies&lt;/code&gt;
object in &lt;code&gt;package.json&lt;/code&gt;, &lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;devDependencies&lt;/code&gt;. You may need to
add this keyword to your &lt;code&gt;package.json&lt;/code&gt; as it is not part of the
auto-generated file.&lt;/p&gt;

&lt;p&gt;Ember&amp;#39;s addon eco-system is getting better every day, and as a community
we are learning as we grow how best to build and maintain addons. I&amp;#39;m
hoping you find these tips helpful. Please feel free to share your own
in the comments below. &lt;/p&gt;
</content>
  </entry><entry>
    <title>The Lean Project</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/19/lean-project-management" />
    <id>https://dockyard.com/blog/2015/03/19/lean-project-management</id>
    <category term="project-management" label="Project Management"/><category term="lean" label="Lean"/><category term="agile" label="Agile"/>
    <published>2015-03-19 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Jon Lacks</name></author>
    <summary>The right recipe of team, process, communication, work environment and pride</summary>
    <content type="html">&lt;p&gt;I am a firm believer in Lean processes aimed to maximize value while minimizing waste. When it comes to running projects in a Lean way, this goes far beyond the role of the Project Manager (or Scrum-master) thus requiring the right recipe of team, process, communication, work environment and pride. Often I am asked what are the typical practices I apply to projects which fall in the mobile/desktop application development context- this is my attempt to answer the question.  &lt;strong&gt;Important disclaimer&lt;/strong&gt; - this is not a prescription for how to run a project, nor does it guarantee success. The secret sauce is always the people NOT the process.&lt;/p&gt;

&lt;h2&gt;The Raw Materials&lt;/h2&gt;

&lt;p&gt;If any of these seem unreasonable, you need to take a hard look at your team and work environment. Any concessions made here will reduce team effectiveness.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A team well-balanced in terms of seniority - Experience is contagious!&lt;/li&gt;
&lt;li&gt;Dedicated team members - not split across multiple projects&lt;/li&gt;
&lt;li&gt;Co-located team members&lt;/li&gt;
&lt;li&gt;Smaller teams (no more than 5-7) â Once you breach this team size communication complexity increases exponentially.&lt;/li&gt;
&lt;li&gt;Conduct retrospectives with full participation - Always seek to get better&lt;/li&gt;
&lt;li&gt;A knowledge management strategy ensures team members know where to store/post directional artifacts that other team members require to do their job (e.g. Wireframes, PSDs, Test Cases, Context Diagrams )&lt;/li&gt;
&lt;li&gt;Use of Information Radiators â Physical views into plans (e.g. Post-Its on a whiteboards) that may supplement a digital plan view&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;1) Breakdown the work&lt;/h2&gt;

&lt;p&gt;Decomposition of capabilities/features is a necessary and somewhat painful evil. However, you do not need to go to a painful level of detail to create this artifact. The importance is breadth not necessarily depth. The depth only needs to go as far as necessary for the team to directionally understand where a feature needs to go. If a team member is able to provide some form of time estimate (best and worst case) for one of those lower level items, you&amp;#39;re low level enough. If estimates are coming out to less than 1 day you have likely gone too far. Get the full team involved, apply the 80/20 rule in terms of completeness and time-box the activity.&lt;/p&gt;

&lt;h2&gt;2) Define a Path&lt;/h2&gt;

&lt;p&gt;Once you have step 1 in place, work with the team to derive a chronological execution of the work driven by perceived value and/or risk/complexity of a given feature. Front loading your risk/complexity (as long as it is somewhat high value) is a very acceptable and smart approach because impact of course correction early on is much less invasive than the alternative. Ensure a basic architecture for the overall solution is derived and communicated. This ensures that the team has a solid foundation to build upon.&lt;/p&gt;

&lt;h2&gt;3) Respect the &lt;a href=&quot;http://en.wikipedia.org/wiki/Project_management_triangle&quot;&gt;Pyramid of constraint&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Scope, Time and Cost â Fundamental variables applicable to any project context. Visibility and active monitoring of these variables is essential to ensure project success. First and foremost, ensure that a baseline is established for each of these variables before a team even start the project. Understand how your stakeholders rate the relative importance of each of these variables and uphold the &amp;quot;Rule&amp;quot; that trade-offs are the only way these baselines can/will adjust. Deferring this activity to after a project gets going can result in scope creep and cost/time over runs.&lt;/p&gt;

&lt;h2&gt;4) Hold up the mirror&lt;/h2&gt;

&lt;p&gt;As a PM, itâs your responsibility to hold up a mirror in front of your team that shows the good, the bad, and the ugly.  This allows the team to maintain appreciation for the big picture while they do their best to work through the small one.   I am huge advocate of a plan view that I have written about in the past (&lt;a href=&quot;http://reefpoints.dockyard.com/2014/07/29/project-carpe-diem.html&quot;&gt;High and Mid-Level Plans&lt;/a&gt;) â which shows time, features, tasks, distribution of work across team capability areas (Design, Backend, UXD, etc.), progress made, unplanned work and deferred work that will come in later releases.  If you have this and revisit it often, consider your team informed and that those Triangle of Constraint variables are being monitored (for the most part.)&lt;/p&gt;

&lt;h2&gt;5) Create an environment of ownership and accountability&lt;/h2&gt;

&lt;p&gt;Everyone is a player. PMâs should be servant leaders, therefore any plan created needs to be the team&amp;#39;s plan not the PMâs (or Sr. Mgmt.)  This way the team has accountability and ownership rights over whatever happens to the plan. If something is not going as planned the team can understand the implications of this and course correct and work to reveal why something may not be working out. Constant readjustment and calibration is required to keep things moving along. The project manager helps ensure these conversations happen.&lt;/p&gt;

&lt;p&gt;No team member can slip into the shadows. To be successful every contributor needs to have a voice. A PM needs to put their âFacilitationâ hats on and ensure they proactively encourage all to participate and chime in on team affairs. Thatâs the beauty of teams. They succeed together, not as individuals.&lt;/p&gt;

&lt;h2&gt;6) Demonstrate Progress&lt;/h2&gt;

&lt;p&gt;Demos encourage quality, because no one wants to demo something that works and looks subpar. Stakeholders  can rest assured they did not buy snake oil and value is being delivered in some regular interval. Demonstrations affirm you&amp;#39;re heading in the right direction.  Last but not least, demos allow the team to celebrate success in short bursts - It feels great to get something done especially when the road ahead is a long one!&lt;/p&gt;

&lt;p&gt;Give it a go and let me know if this works for your team.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Doldrums of Consulting</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/18/the-doldrums-of-consulting" />
    <id>https://dockyard.com/blog/2015/03/18/the-doldrums-of-consulting</id>
    <category term="business" label="Business"/><category term="opinion" label="Opinion"/>
    <published>2015-03-18 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/X6DGygm.jpg&quot; alt=&quot;http://i.imgur.com/X6DGygm.jpg&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Doldrums&lt;/em&gt; is a sailing term. It means when you&amp;#39;re stuck on the
water with no wind. Your only option is to wait for the wind to pick up
so you can continue on your way.&lt;/p&gt;

&lt;p&gt;DockYard is currently in the doldrums.&lt;/p&gt;

&lt;p&gt;Maybe this isn&amp;#39;t something that a consultancy should publicly admit,
but we&amp;#39;ve seen client engagement significantly dry up for us in the past
month and a half. Where we were selling and turning clients away a few
months ago, we are struggling to close a single deal right now. This is
the ebb and flow of consulting, it happens. Our only option is to wait
for the wind to pick up so we can continue on our way.&lt;/p&gt;

&lt;p&gt;I was speaking with a few other software (Ember) consultancies recently
and they voiced similar stories. I am not certain why Ember has seen
such a steep drop off in interest. One theory is that Ember is currently
in the &lt;em&gt;Trough of Sorrow&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/hkzpuBa.png&quot; alt=&quot;http://i.imgur.com/hkzpuBa.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;Does a framework follow similar trends to a startup? Perhaps. In any
event, we&amp;#39;re now trying to diversify our offerings. I announced last
week that DockYard is now offering Staff Augmentation services. This has
piqued some interest but we&amp;#39;re seeing a lot of inquiries for starting a
few months from now.&lt;/p&gt;

&lt;p&gt;It is funny because I know in a month or two we&amp;#39;ll be fine. We just have
to survive the thin times, which is always stressful. How we weather
this will speak a lot about DockYard as a company. It is said the only
way to survive the &lt;em&gt;Trough of Sorrow&lt;/em&gt; is going to be company culture. If
this is true then I&amp;#39;m quite confident in us.&lt;/p&gt;

&lt;p&gt;I also realize that we&amp;#39;re towards the end of a financial quarter.
Companies tend to reach out after the start of a quarter, but if I were
them I wouldn&amp;#39;t wait. If companies were to &lt;a href=&quot;https://dockyard.com/contact&quot;&gt;contact
us&lt;/a&gt; now they would find us in a position that
would be easy to negotiate with.&lt;/p&gt;

&lt;p&gt;I&amp;#39;d be interested in hearing from other shops: have you experienced The
Doldrums? What pulled you through? What strategies have you put in place
to avoid them in the future?&lt;/p&gt;
</content>
  </entry><entry>
    <title>Thriving in a New Work Environment</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/16/thriving-in-a-new-work-environment" />
    <id>https://dockyard.com/blog/2015/03/16/thriving-in-a-new-work-environment</id>
    <category term="opinion" label="Opinion"/><category term="jobs" label="Jobs"/><category term="team" label="Team"/>
    <published>2015-03-16 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Cory Tanner</name></author>
    <summary>Learn how to go beyond expectations at your new job</summary>
    <content type="html">&lt;h2&gt;My Background&lt;/h2&gt;

&lt;p&gt;If you asked me a month and a half ago when I was living and working near Philadelphia as a Director of digital communications, âCory what are the chances that you will be in Boston working for a new company?â. I would have said you were crazy and I couldnât see myself leaving the Philly area unless a company blew me away with their culture and work environment. How would I watch my Sixers, Eagles, and Phillies games if I left the Philly area?&lt;/p&gt;

&lt;p&gt;Then in a week and a half frenzy I was moving up to Boston after it had just snowed another two feet in Boston. A day after that I had moved in to my new apartment and it was my first day at DockYard as a Junior UX Developer!&lt;/p&gt;

&lt;p&gt;Fast forward a week and I had met 16 new DockYard co-workers (who, yes, are crazy smart) and was introduced to a new coding/project management environment. I was then challeneged to learn how to  structure my SCSS with the
&lt;a href=&quot;https://github.com/dockyard/styleguides/blob/master/uxd/class-naming-conventions.md&quot;&gt;BEM&lt;/a&gt;
class naming conventions and rules for Scalable and Modular Architecture for CSS
(&lt;a href=&quot;https://github.com/dockyard/styleguides/blob/master/uxd/beginning-a-project.md&quot;&gt;SMACSS&lt;/a&gt;), all of this  was a tidal wave of new information and personally a different way of thinking.&lt;/p&gt;

&lt;h2&gt;Itâs Not All About You&lt;/h2&gt;

&lt;p&gt;I would love to say that the sole reason that Iâve been able to handle all the new information is that I am purely that awesome. But in reality I could not have gotten through any of this without the work environment DockYard has implemented.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://reefpoints.dockyard.com/2015/01/16/joining-dockyard.html&quot;&gt;Estelle&lt;/a&gt; and
&lt;a href=&quot;http://reefpoints.dockyard.com/office/2013/07/09/first-month-at-dockyard.html&quot;&gt;Marin&lt;/a&gt; explain how âWicked Goodâ the DockYard team is and do so better than I can, but from my experience after a month of working here it is clear that everyone wants to help each other (new guy included). If you need help and youâre not approaching other team members with questions, you might find yourself out of place.&lt;/p&gt;

&lt;p&gt;This type of atmosphere is exactly what you need for soaking in all the information you receive at a new job. You will always have questions and uncertainties in a new environment like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Am I meeting their expectations&lt;/li&gt;
&lt;li&gt;Am I messing this up&lt;/li&gt;
&lt;li&gt;Will I look stupid if I ask this question&lt;/li&gt;
&lt;li&gt;What will they think if...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is inevitable to have these questions when you are in a new work place and you should have them, don&amp;#39;t be afraid to solve those concerns by asking productive questions! The new company you just joined would rather be asked a stupid question then see you running in circles not willing to interact with the team.&lt;/p&gt;

&lt;p&gt;I have asked many questions in my first month here and not once has someone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Said no&lt;/li&gt;
&lt;li&gt;Told me there was no point to my question&lt;/li&gt;
&lt;li&gt;Looked down on me for not knowing something&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a testament to DockYard but also should be how any team should be run, especially web development teams.&lt;/p&gt;

&lt;h2&gt;Success Is Ultimately Decided By You&lt;/h2&gt;

&lt;p&gt;Now itâs not all up to the team you are joining to make you successful, you have to be willing to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Put time into reading about things you did not understand&lt;/li&gt;
&lt;li&gt;Research tools/techniques that you see yourself using in the future&lt;/li&gt;
&lt;li&gt;Be open minded with new development techniques and a new project management process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are successful with goals/projects your boss gives you, then you are meeting your employers standards. In the web development line of work in order to thrive in an environment you should be going above what is expected of you.&lt;/p&gt;

&lt;p&gt;When coworkers look at your work they should be impressed and surprised with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The product you are presenting&lt;/li&gt;
&lt;li&gt;How quick and thorough you are when learning new things&lt;/li&gt;
&lt;li&gt;Contributions you make to current projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you are getting those type of reactions to the list above you are thriving in the new work environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;quot;Thriving in a new work environment comes from working harder and more efficiently than expected&amp;quot;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Be willing to be one of the first people at the office and leave later than most, you want to soak in as much information as you can. When you are given new things to learn tackle them immediately.&lt;/p&gt;

&lt;p&gt;During all the chaos of starting a new job stay organized and keep notes of things you are learning, you will probably not remember that Git command after one or two uses.&lt;/p&gt;

&lt;p&gt;If you find yourself in a new work environment and feel overwhelmed just remember to ask as many questions as you can and work hard to understand the solutions your team provides you.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ask good questions</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/11/ask-good-questions" />
    <id>https://dockyard.com/blog/2015/03/11/ask-good-questions</id>
    <category term="design" label="Design"/><category term="observations" label="Observations"/><category term="quality" label="Quality"/><category term="workflow" label="Workflow"/>
    <published>2015-03-11 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>The only way to get real answers in user interviews for UX design</summary>
    <content type="html">&lt;p&gt;In an &lt;a href=&quot;http://reefpoints.dockyard.com/2015/02/11/managing-the-conversation.html&quot;&gt;earlier post&lt;/a&gt;, I focused on the challenges of leading a good user interview. Today, Iâd like to focus on one rule about asking questions to get reliable results.&lt;/p&gt;

&lt;h2&gt;Ask open-ended questions.&lt;/h2&gt;

&lt;p&gt;Otherwise, the responses you get will be either biased or useless. &lt;/p&gt;

&lt;h2&gt;Let&amp;#39;s look at some interview questions (from worst to best)&lt;/h2&gt;

&lt;p&gt;They appear in order: from least useful to most useful in getting you good responses. For context, imagine youâre doing some user research and you&amp;#39;re in the middle of a project to design some widgets.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;âYou like this widget in green, right? We picked green because itâs calming.â&lt;/strong&gt;
This question is so bad it&amp;#39;s grotesque, but it may still happen to novice interviewers. Not only does the question suggest a specific answer (you like it!), but it also gives reasons why that answer might be the right one (green is calming!) The interviewee is not likely to share a genuine opinion with this much pressure to say âyes, I love it in green!â.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;âHow do you feel about this widget? Do you like its color?â&lt;/strong&gt; Slightly better, but still of limited use. By suggesting a response and allowing the user to narrow it down to a binary yes/no, weâre getting a very limited amount of information back. In addition, likes and dislikes move the conversation into a potentially awkward area. Some people may not be comfortable telling you they donât like something you made.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;âHow do you feel about this widget? What do you think it does?â&lt;/strong&gt; Now, this is better. We are opening up to qualitative responses with lots of detail. By not suggesting options for what an answer might be, we are more likely to get unexpected, valuable results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;âTalk me through what you see here.â&lt;/strong&gt; A super open-ended question, useful in the beginning of an interview. Do they even see the widget?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;âHow would you normally approach (widget-related task)?â&lt;/strong&gt; This seems to be the best opening question for a user interview. While not appropriate for all circumstances, it is great at opening up areas you may not have considered to be in the scope of the project. This question can help reframe the problem you are working to solve.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;âHow did you last (widget-related task)?â&lt;/strong&gt; Past behavior is a more reliable indicator than a behavior people might describe as their normal. So, this re-phrasing can encourage more honest answers. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may notice that it takes more  time to ask open-ended questions. You may trigger your interviewee to share a lot of extra information, not just a concise answer to the question you asked. You may have to follow up with more questions to get to the âwhyâ behind a certain behavior. But with the increased effort comes a better result. The responses are real. They are not influenced by your opinion about the thing youâre asking, because youâve kept that opinion outside the questions. These responses present a more nuanced picture of your usersâ needs and environment.&lt;/p&gt;

&lt;p&gt;I condensed this principle from conference talks, books and workshops I attended over the past few years. Two sources in particular: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/michelleyaiser&quot;&gt;Michelle Yaiser&amp;#39;s&lt;/a&gt; talk on user research at &lt;a href=&quot;http://uxeast.org/&quot;&gt;UX Camp&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://shop.npr.org/sound-reporting&quot;&gt;Sound reporting : the NPR guide to audio journalism and production&lt;/a&gt;. This book is outside of the usual UX Design reading list, but it&amp;#39;s useful for interviewing skills. It shows how much  effort and consideration it takes a journalist to gather information in a neutral, ethical way.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It&amp;#39;s almost always a better investment of your time to conduct a few in-depth, âdifficultâ and neutral interviews, than to rush many interviewees through surface-level questions. This is especially true at the beginning of a project, when more design options are open. Your effort to keep the process unbiased will yield quality results, and quality wins.&lt;/p&gt;
</content>
  </entry><entry>
    <title>DockYard is now accepting staff augmentation Ember.js contracts</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/09/dockyard-is-now-accepting-staff-augmentation-ember-js-contracts" />
    <id>https://dockyard.com/blog/2015/03/09/dockyard-is-now-accepting-staff-augmentation-ember-js-contracts</id>
    <category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/>
    <published>2015-03-09 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Over the past three years DockYard has primarily taken on &amp;quot;greenfield&amp;quot;
projects, where we are responsible for building applications from
scratch through design, development, and launch. Starting today we&amp;#39;re
adding Ember.js Staff Augmentation to the services we provide to our
clients.&lt;/p&gt;

&lt;p&gt;If you are looking to add an Ember.js expert to help your team you
should contact us. Our entire engineering team is extremely experienced
in Ember.js application development, Ember.js best practices, and Ember.js Test Driven
Development. We can help your team finish existing features, guide
your team on how to properly build an Ember.js application, and help you
hit your delivery deadline.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dockyard.com/contact&quot;&gt;Visit our contact page and choose
&amp;quot;Staff Augmentation&amp;quot; for the Budget&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>EmberConf 2015 Day 2</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/04/ember-conf" />
    <id>https://dockyard.com/blog/2015/03/04/ember-conf</id>
    <category term="ember" label="Ember.js"/>
    <published>2015-03-04 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Marin Abernethy</name></author>
    <summary>Live blog of EmberConf 2015</summary>
    <content type="html">&lt;h1&gt;Fault Tolerant UX by Dan Gebhardt&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dgeb&quot;&gt;@dgeb&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users should be shielded from any application issues that are encountered&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Transaction UX&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Atomic: all or nothing

&lt;ul&gt;
&lt;li&gt;Ex. if a user fills out a form your app should save all the data, not just some.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Consistent: move between different states&lt;/li&gt;
&lt;li&gt;Isolated: allows concurrent changes&lt;/li&gt;
&lt;li&gt;Durable: changes are persisted&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Apps MUST NOT violate the rules of transactional UX or you are violating the users trust&lt;/h3&gt;

&lt;h2&gt;Forgiving User Experience&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fault Tolerant UX --&gt; Forgiving UX&lt;/li&gt;
&lt;li&gt;Transitional experience: to persist data that has not yet be saved, but in the process of being edited&lt;/li&gt;
&lt;li&gt;Undo/redo&lt;/li&gt;
&lt;li&gt;Offline support&lt;/li&gt;
&lt;li&gt;Asynchronous interface (non-blocking)

&lt;ul&gt;
&lt;li&gt;user can make changes as quickly as possible (changes can be queued up and synced at your apps convenience)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Engineering Fault Tolerant UX&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ember provides simple elgant patterns for building a consistent UX&lt;/li&gt;
&lt;li&gt;Similarly, ember data provides durable UX&lt;/li&gt;
&lt;li&gt;Ember data requires customization (extra code) to provide atomic and isolated code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/orbitjs&quot;&gt;Orbit&lt;/a&gt;&lt;/h2&gt;

&lt;h3&gt;Orbit application patterns&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Client first development&lt;/li&gt;
&lt;li&gt;Pluggable sources&lt;/li&gt;
&lt;li&gt;Data synchronization&lt;/li&gt;
&lt;li&gt;Editing contexts&lt;/li&gt;
&lt;li&gt;Undo/redo&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;&lt;a href=&quot;https://github.com/orbitjs/ember-orbit&quot;&gt;ember-orbit&lt;/a&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Provides a store with synchronous and asynchronous methods&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Aligning Ember with Web Standards by Matthew Beale&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/mixonic&quot;&gt;@mixonic&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Standards&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The JS standardization process is about to change: ES5, ES6, ES2015!&lt;/li&gt;
&lt;li&gt;Standards Process

&lt;ul&gt;
&lt;li&gt;5 stages - strawman, proposal(polyfills), draft(experimental), candidate(compliant), finished(shipping)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://remysharp.com/2010/10/08/what-is-a-polyfill&quot;&gt;Polyfill&lt;/a&gt;: A polyfill is a piece of code (or plugin) that provides the technology that you expect the browser to provide natively. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;2 major standards groups:

&lt;ul&gt;
&lt;li&gt;WHATWG + W3C (html / dom related)&lt;/li&gt;
&lt;li&gt;TC39 + Ecma International (promises, classes, for loops, etc)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Aligning with standards is not a one time event. It is ongoing!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Why Standards?&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The goal is productivity&lt;/li&gt;
&lt;li&gt;Standards are portable, reflect best preactices, and endure &lt;/li&gt;
&lt;li&gt;Participants win&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;ES5 -&gt; ES2015&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;New API for maps&lt;/li&gt;
&lt;li&gt;Promises&lt;/li&gt;
&lt;li&gt;Proxies&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Babel&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Babel will turn your ES6+ code into ES5 friendly code

&lt;ul&gt;
&lt;li&gt;Enables new syntax (fat arrow, let) , APIs (map, set), not everything&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Aligning Ember&amp;#39;s Object Model&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt; is this feature: stable? a good pattern? implemented correctly? implemented performantly?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;ES Classes&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Three new tools: class, extend, super&lt;/li&gt;
&lt;li&gt;More gotchas: 

&lt;ul&gt;
&lt;li&gt;setUnknownProperty &lt;/li&gt;
&lt;li&gt;Transpiler output&lt;/li&gt;
&lt;li&gt;New syntax&lt;/li&gt;
&lt;li&gt;Changes in way that super behaves&lt;/li&gt;
&lt;li&gt;Mixins&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember: standards are a two-way street!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.201-created.com/ember-community-survey-2015&quot;&gt;Ember Community Survey&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Growing Ember One Tomster at a Time by Jamie White&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/jgwhite&quot;&gt;@jgwhite&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How did a tech community come to be so vibrant? How can we continue?&lt;/p&gt;

&lt;h2&gt;1. The Tomster&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Representation of productivity and friendliness&lt;/li&gt;
&lt;li&gt;Tomster wore different hats

&lt;ul&gt;
&lt;li&gt;Custom tomsters&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Good defaults

&lt;ul&gt;
&lt;li&gt;Having a friendly mascot makes things easier.&lt;/li&gt;
&lt;li&gt;âAmbitionâ and âfriendlinessâ is hard to juxtapose&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Composing concepts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;2. Language&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tomster is a tool. Productivity and friendliness implicitly part of conversation

&lt;ul&gt;
&lt;li&gt;Words stick; the right words enable conversations&lt;/li&gt;
&lt;li&gt;âhackâ is not a good vocabulary word - negative connotation &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;3. User Interface&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Programming language and documentation with good user interface&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;4. Hackability&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Parts have to be accesible - has to feel hackable.

&lt;ul&gt;
&lt;li&gt;Tomster was not overly done.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;5. Roles&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Many specialisms in Ember Community: documenteer, student, mentor, critic, explorer, and many more!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Community building is a design and engineering challenge&lt;/p&gt;

&lt;h1&gt;Interaction Design with Ember 2.0 and Polymer by Bryan Langslet&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/blangslet&quot;&gt;@blangslet&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The web browser is the largest app runtime in the world, and will continue to grow&lt;/li&gt;
&lt;li&gt;Every device has to be connected to the web&lt;/li&gt;
&lt;li&gt;Web frameworks and toolkits are getting closer to native performance everyday &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;quot;How can I - one person with a laptop - leverage my time as powerfully as I possibly can, every minute I work?&amp;quot;&lt;/p&gt;

&lt;h2&gt;Ember-Flow&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A paradigm shift for web interaction design&lt;/li&gt;
&lt;li&gt;The goal: to blur the lines between native and web applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Web Components&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Extends the browser itself

&lt;ul&gt;
&lt;li&gt;Polymer components extend a base component&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Encapsulation&lt;/li&gt;
&lt;li&gt;Declarative&lt;/li&gt;
&lt;li&gt;True reusability/portability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Ember vs. Polymer Use Cases:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ember: developer productivity, conventions&lt;/li&gt;
&lt;li&gt;Ember: community&lt;/li&gt;
&lt;li&gt;Ember: World-class routing and state management&lt;/li&gt;
&lt;li&gt;Polymer: constantly pushing the web forward&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Web Animations API&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Has the best of both CSS and javascript animations&lt;/li&gt;
&lt;li&gt;Web animations run outside of the main thread and can be accelerated on the GPU&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;&lt;a href=&quot;https://github.com/blangslet/treasure-hunt&quot;&gt;Treasure Hunt Demo Application&lt;/a&gt;&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&amp;quot;Demonstrates an experimental integration between ember.js routing and Polymer&amp;#39;s core-animated-pages component to create beautiful inter-state animated transitions&amp;quot;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Building Applications for Custom Environments with Ember CLI by Brittany Storoz&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/brittanystoroz&quot;&gt;@brittanystoroz&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Ember CLI&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Everyones favorite command line tool&lt;/li&gt;
&lt;li&gt;Build organized ember apps quickly&lt;/li&gt;
&lt;li&gt;Fills huge void in toolset for JS devs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Ember CLI Addons&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Extend ember-cli beyond core fucntionality&lt;/li&gt;
&lt;li&gt;Follow standard npm conventions&lt;/li&gt;
&lt;li&gt;Easy to create &amp;amp; install:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;ember addon name-of-your-addon&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ember install:addon name-of-your-addon&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;Firefox OS&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Requirements that Ember CLI could not provide

&lt;ol&gt;
&lt;li&gt;Generate and validate a manifest file (same concept as package.json)&lt;/li&gt;
&lt;li&gt;UI components that mimic OS interface&lt;/li&gt;
&lt;li&gt;Publish to Firefox marketplace&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;Ember CLI Addon was born to fill those requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;1st Requirement: Generating The Manifest&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Creating Blueprints

&lt;ul&gt;
&lt;li&gt;rules for generating common code and file structures:&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;ember generate blueprint name-of-blueprint&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;2nd Requirement: FirefoxOS UI (&lt;a href=&quot;https://github.com/gaia-components/gaia-tabs&quot;&gt;Gaia&lt;/a&gt;)&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Building components
&lt;code&gt;bower install gaia-components/gaia-stubs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;2 responsibilities:

&lt;ul&gt;
&lt;li&gt;including dependencies and creating the addon&lt;/li&gt;
&lt;li&gt;making both available to the consuming application&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Components Review&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dependencies:

&lt;ul&gt;
&lt;li&gt;bower install within addon&lt;/li&gt;
&lt;li&gt;bower install withing consuming logic&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Component logic

&lt;ul&gt;
&lt;li&gt;create component&lt;/li&gt;
&lt;li&gt;export components to consuming aplication&lt;/li&gt;
&lt;li&gt;define component template&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Validation &amp;amp; Publishing

&lt;ul&gt;
&lt;li&gt;creating commands for control over when these things happen&lt;/li&gt;
&lt;li&gt;&lt;code&gt;includedCommands&lt;/code&gt; hook: returns object of commands which are found inside &lt;code&gt;lb/commands&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ember help&lt;/code&gt; lists out information about available add-on commands. And lots more useful info.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Building Real-time Applications with Ember by Steve Kinney&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/stevekinney&quot;&gt;@stevekinney&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrating browser functionality and third party code into our applications. In this case, WebSockets.&lt;/li&gt;
&lt;li&gt;What is a WebSocket Used for? 

&lt;ul&gt;
&lt;li&gt;Collaboration, analytics dashboards, prompting user to upgrade application&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Can I actually use WebSockets? 

&lt;ul&gt;
&lt;li&gt;For the most part, yes (some earlier version of IE not supported)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Socket.io -&gt; library for Node&lt;/li&gt;
&lt;li&gt;Faye  -&gt; simple pub/sub messaging&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Approach #1: Use Standalone Controller&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Somewhat limited because it only works between controllers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Approach #2: Dependency Injection with Services&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ember generate service websocket&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Declare where you want to inject it inside the Initializer&lt;/li&gt;
&lt;li&gt;Inside controller: &lt;code&gt;websocket: Ember.inject.service()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Approach #3 Using Socket.io&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Socket.io is both a server and client side library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;bit.ly/js-poll&quot;&gt;What is your favorite thing about JavaScript?&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Minitalks!&lt;/h1&gt;

&lt;h2&gt;1. Measuring Performance with User Timing API by Bill Heaton&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/pixelhandler&quot;&gt;@pixelhandler&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Measuring the differences in template rendering speeds between Ember.js v1.8.1 w/Handlebars v1.3 and Ember.js v1.10.0 w/HTMLBars&lt;/li&gt;
&lt;li&gt;Check out his findings on &lt;a href=&quot;http://pixelhandler.com/posts/measuring-performance-with-user-timing-api-in-an-ember-application&quot;&gt;blog!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;2. &lt;code&gt;ember-islands&lt;/code&gt; by Mitch Lloyd&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/mitchlloyd&quot;&gt;@mitchlloyd&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mitchlloyd/ember-islands&quot;&gt;&lt;code&gt;ember-islands&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Render Ember components UJS-style to achieve &amp;quot;Islands of Richness&amp;quot;. You can arbitrarily render Ember components in the body of the page and they will all be connected to the same Ember app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;3. Ember Testing with Chemistry Dog by Liz Bailey&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/lizzerdrix&quot;&gt;@lizzerdrix&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Migration from Rails to Ember&lt;/li&gt;
&lt;li&gt;Ember does not provide as much documentation on testing&lt;/li&gt;
&lt;li&gt;Would love to help make Ember more approachable to beginners&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;4. Running C++ in ember-cli with Emscripten by Michael Nutt&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/mnutt&quot;&gt;@mnutt&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/movableink/ember-cli-emscripten&quot;&gt;&lt;code&gt;ember-cli-emscripten&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Allows you to add C or C++ to your ember app, then require the exposed functions and classes.&lt;/li&gt;
&lt;li&gt;Fibonacci sequence demo!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;5. Ember Observer by Kate Gengler&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/kategengler&quot;&gt;@kategengler&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/emberobserver/client&quot;&gt;Ember Observer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gives addons a score out of 10&lt;/li&gt;
&lt;li&gt;pulls hourly from npm and Github&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;6. CSS is Hard by Erik Bryn&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ebryn&quot;&gt;@ebryn&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ebryn/ember-component-css&quot;&gt;&lt;code&gt;ember-component-css&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;namespaces our component styles automatically!&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Physical Design by Edward Faulkner&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ef4&quot;&gt;@ef4&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Computers are so abstract. Possibilities are endless, only hindered by your imagination.&lt;/li&gt;
&lt;li&gt;Constrained by physics&lt;/li&gt;
&lt;li&gt;Googles material design spec

&lt;ul&gt;
&lt;li&gt;does not break rules of physics&lt;/li&gt;
&lt;li&gt;animations and motion appeal to us because they fit into our idea of how it should physically work.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ef4/liquid-fire&quot;&gt;Liquid Fire&lt;/a&gt; live demo!

&lt;ul&gt;
&lt;li&gt; &lt;code&gt;npm install âsave-dev liquid-fire&lt;/code&gt; for Ember 1.11+&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://miguelcobain.github.io/ember-paper&quot;&gt;Ember Paper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Closing Keynote: Chris Eppstein&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/chriseppstein&quot;&gt;@chriseppstein&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Announcing: Eyeglass&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Distribute SASS extensions as NPM modules for &lt;a href=&quot;https://github.com/sass/libsass&quot;&gt;LIBSASS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Will be able to integrate with a number of different build systems, including Ember CLI&lt;/li&gt;
&lt;li&gt;Major performance improvements&lt;/li&gt;
&lt;li&gt;The best parts of SASS and Compass, working with the best tools JS has to offer&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;A Selection of Chris&amp;#39; Inspirational Messages&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&amp;quot;Don&amp;#39;t be a Sasshole&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;People come to a community for the tech, but stay for the love!&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Sass didn&amp;#39;t lose when I started ignoring the haters&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;If you use a framework you love, you&amp;#39;ll never work a day in your life&amp;quot;&lt;/li&gt;
&lt;li&gt;&amp;quot;Secret to a vibrant community: be excellent to eachother&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry><entry>
    <title>EmberConf 2015 Day 1</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/03/03/ember-conf" />
    <id>https://dockyard.com/blog/2015/03/03/ember-conf</id>
    <category term="ember" label="Ember.js"/>
    <published>2015-03-03 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Marin Abernethy</name></author>
    <summary>Live blog of EmberConf 2015</summary>
    <content type="html">&lt;h1&gt;Opening Keynote: Tom Dale and Yehuda Katz&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;To kick off the conference Tomster joined Tom Dale and Yehuda Katz on stage!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mixonic&quot;&gt;@mixonic&lt;/a&gt; &lt;a href=&quot;https://github.com/ef4&quot;&gt;@ef4&lt;/a&gt; &lt;a href=&quot;https://github.com/mmunm&quot;&gt;@mmun&lt;/a&gt; were welcomed as new members to the Ember Core Team&lt;/li&gt;
&lt;li&gt;Big thanks to Robert Jackson &lt;a href=&quot;https://github.com/rwjblue&quot;&gt;@rwjblue&lt;/a&gt;!!!! &lt;a href=&quot;http://getrwjblueabeer.com&quot;&gt;Get rwjblue a beer!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Ember 2014 in Review&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rapid Release worked great! 6 week release cycle to get new features into everyone&amp;#39;s hands.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;HTMLBars&lt;/h3&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;a href={{url}}&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;instead of&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;a {{bindAttr href=&amp;quot;url&amp;quot;}}&amp;gt; 
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Block parameters, faster and lower memory, validation for templates&lt;/li&gt;
&lt;li&gt;Killed metamorphs!&lt;/li&gt;
&lt;li&gt;Improvements to Ember Inspector including Ember Data and promises pane, render performance tab, multiple &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;s, and redesigned UI, to name a few.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Ember CLI&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Single install command for Addons, test support, massive performance improvements, and API stubbing, and server proxy (the list goes on!).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Testing Ecosystem&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;handles asynchrony &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Ember Data&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Relationship syncing, async relationships - built with async loading in mind.&lt;/li&gt;
&lt;li&gt;Adapter Ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;That was last year, what&amp;#39;s next?&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://guides.emberjs.com&quot;&gt;Versioned Guides&lt;/a&gt; -- live today!&lt;/li&gt;
&lt;li&gt;Next Version of Ember CLI (as of last night)&lt;/li&gt;
&lt;li&gt;Engines&lt;/li&gt;
&lt;li&gt;List View&lt;/li&gt;
&lt;li&gt;&lt;angle-bracket&gt; Components (already in Canary)&lt;/li&gt;
&lt;li&gt;Liquid Fire&lt;/li&gt;
&lt;li&gt;Async and Routable Components&lt;/li&gt;
&lt;li&gt;Ember Data: JSON API support out of the box&lt;/li&gt;
&lt;li&gt;Pagination and Filtering&lt;/li&gt;
&lt;li&gt;Shipping Ember Data 1.0&lt;/li&gt;
&lt;li&gt;6/12 release date for Ember 2.0, Ember Inspector, Ember CLI, LiquidFire, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Ember.js Performance by Stefan Penner&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/stefanpenner&quot;&gt;@stefanpenner&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Important choices to make, how to make the right choices?&lt;/li&gt;
&lt;li&gt;Time vs. Space&lt;/li&gt;
&lt;li&gt;Things that are costly in space: closures, objects, non-optimized code, compiled code, excess shape allocations&lt;/li&gt;
&lt;li&gt;In Ember.js, need to do less work, align with primitives&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Mis-alignment #1&lt;/h2&gt;

&lt;p&gt;Problem: Ember does too much work.&lt;/p&gt;

&lt;p&gt;Solution: do less&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actions up, bindings down, no two-way bindings, explicit data flow&lt;/li&gt;
&lt;li&gt;RIP singleton controllers, explicit lifecycle&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Mis-alignment #2&lt;/h2&gt;

&lt;p&gt;Problem: &lt;code&gt;init&lt;/code&gt; and &lt;code&gt;super&lt;/code&gt; are hard to learn and mis-aligned with ES2015&lt;/p&gt;

&lt;p&gt;Solution: Embrace super&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicit defaults in super&lt;/li&gt;
&lt;li&gt;Don&amp;#39;t set properties until super&lt;/li&gt;
&lt;li&gt;When to call &lt;code&gt;_super()&lt;/code&gt;: When overwriting a framework method before touching &lt;code&gt;this&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Mis-alignment #3&lt;/h2&gt;

&lt;p&gt;Problem: Ember.Object.reopen, buggy, complex internals, massive allocations &amp;amp; shapes&lt;/p&gt;

&lt;p&gt;Solution: Limit reopen to before first instantiation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Meta is a good thing. Every class has a meta, every instance has a meta. Metas for instances are what kill us. Meta is &amp;quot;live&amp;quot; inheriting. If can limit reopen, can make all metas one shape.&lt;/li&gt;
&lt;li&gt;meta.listeners is crazier&lt;/li&gt;
&lt;li&gt;Solution: work with V8 to make things better&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Designing for Ember Apps by Steve Trevathan&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/strevat&quot;&gt;@strevat&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mental models: Understand where the user is coming from and what kinds of interactions they deal with

&lt;ul&gt;
&lt;li&gt;&amp;quot;What I think the thing is&amp;quot;&lt;/li&gt;
&lt;li&gt;Influenced by experiences from the past&lt;/li&gt;
&lt;li&gt;Not always solid: can be updated and changed. (improvements)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;2 types of mental models

&lt;ul&gt;
&lt;li&gt;Macro: what I think it is from a distance.&lt;/li&gt;
&lt;li&gt;Micro: how I think each individual interaction works; the specific feature.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Build a framework of understanding

&lt;ul&gt;
&lt;li&gt;Some apps are just too complicated&lt;/li&gt;
&lt;li&gt;Use explicitly if they apply&lt;/li&gt;
&lt;li&gt;Break mental models if it improves the experience&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Design Patterns&lt;/h2&gt;

&lt;h3&gt;#1 Gradual Engagement&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Core value given for free. Eventually you may be asked to sign up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;#2 Skeleton UI&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ex. Google maps: grid becomes fully rendered map.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;#3 Carry Context&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ex. rdio: music played on laptop is reflected on iPad (or other devices). &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;#4 Reuse Core Interactions&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ex. Browsing Pinterest: provides click and follow tangent.&lt;/li&gt;
&lt;li&gt;Micro becomes Macro; core interactions become a symbol of your app.&lt;/li&gt;
&lt;li&gt;&amp;quot;When I go home and think of your app, I think of the experience, the micro features more than the macro ones.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;#5 Offline Mode&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ex. Google Docs: âtrying connectâ message and canât interact with document. Incredibly Frustrating.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Tools of the Trade&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A free design pattern library for Ember apps. &lt;a href=&quot;http://toolsofthetrade.dockyard.com&quot;&gt;Sign up!!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Hijaking Hacker News with Ember.js by Godfrey Chan&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/chancancode&quot;&gt;@chancancode&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Being a canadian is awesome&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/chancancode/hn-reader&quot;&gt;Hijacking Hacker News App&lt;/a&gt;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Browser extension that transforms old site design to new, more usable app&lt;/li&gt;
&lt;li&gt;Runs in hacker news domain&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Getting the Data&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$.get(&amp;quot;/news&amp;#39;).then()&lt;/code&gt;: request html page, extract data, then manipulate&lt;/li&gt;
&lt;li&gt;Hacker News HTML Scrapper: need adapter to help talk to Ember Data store; customize adapter and serializer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Fixing the URLs&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Hacker News urls are not ideal for building an Ember app.&lt;/li&gt;
&lt;li&gt;HN urls (serialized App States) to Ember Router (Actual App States)

&lt;ul&gt;
&lt;li&gt;trick Ember into seeing URLs that are different from what is in the address bar&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Router location types: &lt;code&gt;Ember.HistoryLocation&lt;/code&gt; vs. &lt;code&gt;Ember.HashLocation&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Can use same mechanism to make a custom Ember.Location: &lt;code&gt;App.HackerNewsLocation = Ember.Location.extend()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Preferences&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Changing preferences in one place and can see changes reflected in other

&lt;ul&gt;
&lt;li&gt;Use observer pattern&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;The Possibilities&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What if your ideas do not line up with the framework&amp;#39;s choices?&lt;/li&gt;
&lt;li&gt;If the frameworks is doing it&amp;#39;s job, than the possibilities should be endless!&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;The Art of Ember App Deployment by Luke Melia&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/lukemelia&quot;&gt;@lukemelia&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need to adjust deployment techniques from &amp;quot;server app&amp;quot; days&lt;/li&gt;
&lt;li&gt;When traffic starts routing to the new app, finger-printed assets can no longer be accessed

&lt;ul&gt;
&lt;li&gt;Need to keep old and new finger printed assets for a few minutes after a deploy.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Versioning&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Learn from native apps - phones run different versions of an app&lt;/li&gt;
&lt;li&gt;Keep API working for older clients through API versioning&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Deployment &amp;amp; serving strategy&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;HTML page should be managed and deployed as part of static asset deployment process&lt;/li&gt;
&lt;li&gt;HTML page should be served by the API server&lt;/li&gt;
&lt;li&gt;Preview before activating&lt;/li&gt;
&lt;li&gt;A/B Testing

&lt;ul&gt;
&lt;li&gt;Setting global flags based on A/B buckets&lt;/li&gt;
&lt;li&gt;Serving up wholly different HTML based on A/B bucket&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Notify connected clients&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The New &lt;a href=&quot;github.com/ember-cli/ember-cli-deploy&quot;&gt;&lt;code&gt;ember-cli-deploy&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Merged these three projects: &lt;code&gt;ember-deploy&lt;/code&gt;, &lt;code&gt;front-end-builds&lt;/code&gt;, &lt;code&gt;ember-cli-deploy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Now, one project with 6 maintainers (and growing!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Roadmap&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Release 0.4.0 by the end of this week!&lt;/li&gt;
&lt;li&gt;Reelease 0.5.0 

&lt;ul&gt;
&lt;li&gt;New pipeline hooks and plugins architecture&lt;/li&gt;
&lt;li&gt;Includes post-deploy hook&lt;/li&gt;
&lt;li&gt;Documentation for plugin developers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ember-cli-front-end-builds&lt;/code&gt; becomes a plugin&lt;/li&gt;
&lt;li&gt;USAGE: &lt;code&gt;ember deploy staging&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Beyond 0.5.0: deployment to named buckets, support A/B tests, beta testing, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Ambitious UX for Ambitious Apps by Lauren Tan&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/poteto&quot;&gt;@poteto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good Design is:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;* how it works
* reactive
* playful
* informative
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Designing the product vs. designing the experience&lt;/li&gt;
&lt;li&gt;You are not the same as your website users&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Good Design is Reactive&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Instant feeback&lt;/li&gt;
&lt;li&gt;Flow of data and maintaining relationships between that data&lt;/li&gt;
&lt;li&gt;Ember allows reactivity through the observer pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;The Observer Pattern&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Computed properties transform properties and keep relationships in sync&lt;/li&gt;
&lt;li&gt;Computed Property Macros to keep things DRY.

&lt;ul&gt;
&lt;li&gt;Ember ships with a bunch of these out of the box (map, mapBy, concat, etc)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Observers synchronously invoked when dependent properties change&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Good design is playful&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Has personality&lt;/li&gt;
&lt;li&gt;Ex. Slack when you open app (fun messages)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Good Design is Informative&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Visibility of System Status

&lt;ul&gt;
&lt;li&gt;Jakob Nielson - 10 heuristics for User Interface Design&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Ex. Flash messages

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/poteto/ember-cli-flash&quot;&gt;&lt;code&gt;ember-cli-flash&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Good Design is Intuitive&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop (trello, Google Calendar, etc...)&lt;/li&gt;
&lt;li&gt;Ember handles drag and drop events out of the box

&lt;ul&gt;
&lt;li&gt;add &lt;code&gt;draggable=true&lt;/code&gt; to any html element to make it draggable&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Bring Sanity to Frontend Infastructure with Ember by Sam Selikoff&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/samselikoff&quot;&gt;@samselikoff&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;How Ember Can Help Today:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ember and Ember CLI helps infastructure by reducing boilerplate&lt;/li&gt;
&lt;li&gt;Similar directory structure and architecture&lt;/li&gt;
&lt;li&gt;Conventions: eliminate trivial differences that hold us back&lt;/li&gt;
&lt;li&gt;Writing add-ons for shareable code. Allows us to build structure.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;ember deploy&lt;/code&gt; to deploy apps. Auth and backend config work into separate deploy server.&lt;/li&gt;
&lt;li&gt;Testing in Ember using &lt;code&gt;ember test&lt;/code&gt;. QUnit provides helpers.&lt;/li&gt;
&lt;li&gt;Identify redundancies and abstractions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;How Ember Can Help Tomorrow:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Semantic versioning and CLI conventions&lt;/li&gt;
&lt;li&gt;Flexibility&lt;/li&gt;
&lt;li&gt;New standards and best practices

&lt;ul&gt;
&lt;li&gt;generally, shared solutions/frameworks help identify and discover ways of improving applications&lt;/li&gt;
&lt;li&gt;Ember always keeps up to date with these best practices&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;âEmber is not just a framework, itâs a philosophyâ of how to create and improve software

&lt;ul&gt;
&lt;li&gt;First, give real developers the tools to tinker&lt;/li&gt;
&lt;li&gt;Then, deliberately fold in shared solutions&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, innovate &amp;amp; share!&lt;/p&gt;

&lt;h1&gt;Dynamic Graphic Composition In Ember by Chris Henn&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/chnn&quot;&gt;@chnn&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Spliting a Statistical Graphic into Parts&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Splitting a problem allows us to change one feature of the graphic at a time&lt;/li&gt;
&lt;li&gt;Suggests the aspects of a plot that are possible to change&lt;/li&gt;
&lt;li&gt;Encourages custom visualizations for every data situation&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Demo: &lt;a href=&quot;https://github.com/chnn/composing-graphics&quot;&gt;Scatterplot example&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Adds multiple regression lines (in example, based on # of cylinders of each car)&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{#each subset as |subset|}}
  // component
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Each point in the graph is an svg circle&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Grammer of Graphics by Hadley Wickham&lt;/h3&gt;

&lt;p&gt;(Book of guidlines to follow)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data to Aesthetic Mappings&lt;/li&gt;
&lt;li&gt;Scales: one per Asthetic mapping

&lt;ul&gt;
&lt;li&gt;Each data to aesthetic mapping has some mapping function&lt;/li&gt;
&lt;li&gt;he has chosen to represent these as points in scatterplot example&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Layers: geom, stat, optional data to aesthetic mapping&lt;/li&gt;
&lt;li&gt;Coordinate System&lt;/li&gt;
&lt;li&gt;Faceting&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;What does this look like using Ember?&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Data to Aesthetics = outer layer component which takes in the data as params&lt;/li&gt;
&lt;li&gt;Scales = computed properties (using computer property macros)&lt;/li&gt;
&lt;li&gt;Layers = looks like top level component, but must pass the scales&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Further Considerations&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Interactivity&lt;/li&gt;
&lt;li&gt;Animations and transitions

&lt;ul&gt;
&lt;li&gt;performance (updating graphic many times per second)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Test-Driven Development By Example by Toran Billups&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/toranbn&quot;&gt;@toranb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live coding!!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Red, green, refactor

&lt;ul&gt;
&lt;li&gt;You get a lot of feedback from red (so it can be red, red, red, green, refactor)&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Incorrect selector in template to make sure youâre doing it correctly (aka. test should fail)&lt;/li&gt;
&lt;li&gt;Test should not be very layout dependent

&lt;ul&gt;
&lt;li&gt;Should be more general and not break whenever you make template changes that do not change app functionality.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Test names should be descriptive&lt;/li&gt;
&lt;li&gt;Testing computed properties is recommended because of how caching works with them. Failing test will let you know which properties should be observed in order to break the cache.&lt;/li&gt;
&lt;li&gt;Design proof testing&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry><entry>
    <title>Rubyist&#39;s Guide to Executing JavaScript</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/02/24/rubyists-guide-to-executing-javascript" />
    <id>https://dockyard.com/blog/2015/02/24/rubyists-guide-to-executing-javascript</id>
    <category term="ruby" label="Ruby"/><category term="javascript" label="JavaScript"/>
    <published>2015-02-24 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Michael Dupuis</name></author>
    <summary>A high-level look at how your Ruby and JavaScript code gets executed.</summary>
    <content type="html">&lt;p&gt;JavaScript is introduced to developers as a programming language that runs client-side, in the browser. This is convenient as a jumping off point for aspiring programmers, who can simply open up Chromeâs Web Inspector and start alerting âHello, World!â, but itâs a concept that isnât easy to unpack. Soon enough, the developer will likely find herself in contact with JavaScript outside of the browser â Node.js being the most prominent example of this. At this point, the notion of JavaScript being a language for the browser is no longer helpful; it obfuscates what is happening when a developer executes a line of code.&lt;/p&gt;

&lt;p&gt;This post is a high level primer on what is happening âunder the hoodâ with our code. It will lend some insight into what terminology like âtokenizing,â âinterpreting,â âcompiling,â and a host of other terms mean. You&amp;#39;ll gain a better sense of what the concept of a virtual machine encapsulates. And hopefully you&amp;#39;ll leave with a better understanding of what your script is doing before it hits your computer&amp;#39;s processor.&lt;/p&gt;

&lt;p&gt;I feel this article will be well-suited for Rubyists who find themselves increasingly working in the realm of JavaScript, as Iâll be comparing how code executes between the two languages.&lt;/p&gt;

&lt;p&gt;Rather than explaining how a line of Ruby or JavaScript code gets processed and run, Iâd like to work our way backwards, beginning with machine code. When you write a line of Ruby, it doesnât simply go to the processor when you run the script. It goes through a number of translations before being turned into machine code that the processor can execute. Weâll look at how Ruby gets processed and then touch on how JavaScript differs.&lt;/p&gt;

&lt;h2&gt;Ruby&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/Sa1qURz.png&quot; alt=&quot;Ruby execution diagram&quot;&gt;&lt;/p&gt;

&lt;h3&gt;Machine code&lt;/h3&gt;

&lt;p&gt;Machine code is binary that is executed directly by your computerâs CPU. The bit patterns correspond directly to the architecture design of the processor.&lt;/p&gt;

&lt;p&gt;Before a statement in a scripted language becomes machine code, it gets compiled into machine code by a compiler.&lt;/p&gt;

&lt;h3&gt;Virtual Machine&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://www.aosabook.org/en/llvm.html&quot;&gt;LLVM&lt;/a&gt; compiles code on most
Unix-based machines. It generates the machine code for the processor
during compilation, which is just the process of translating one language to another.&lt;/p&gt;

&lt;p&gt;The virtual machine executes your code. It&amp;#39;s written in C and is known as the &lt;a href=&quot;http://en.wikipedia.org/wiki/YARV&quot;&gt;YARV&lt;/a&gt; interpreter. It is at the heart of a scripting languages &amp;quot;implementation,&amp;quot; as it executes the source code via whatever language the scripting language is built upon (&lt;a href=&quot;http://en.wikipedia.org/wiki/C_(programming_language)&quot;&gt;C&lt;/a&gt; in the case of &lt;a href=&quot;http://en.wikipedia.org/wiki/Ruby_MRI&quot;&gt;Ruby MRI&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;YARV doesnât receive the Ruby statement as you typed it. It goes through an abstraction of your code known as an &lt;a href=&quot;http://en.wikipedia.org/wiki/Abstract_syntax_tree&quot;&gt;Abstract Syntax Tree (AST)&lt;/a&gt;, which get compiled to YARV byte code and run.&lt;/p&gt;

&lt;p&gt;This &amp;quot;tree&amp;quot; is made up of nodes assembled by something called the parser.&lt;/p&gt;

&lt;h3&gt;Parser&lt;/h3&gt;

&lt;p&gt;You can think of a node on the Abstract Syntax Tree as an atomic representation of a Ruby grammar rule. The reason that Ruby knows to print âHello, Worldâ when it sees &lt;code&gt;print &amp;#39;Hello, World&amp;#39;&lt;/code&gt; is because the parser knows that &lt;code&gt;print&lt;/code&gt; is a method and the string &lt;code&gt;&amp;#39;Hello, World&amp;#39;&lt;/code&gt; is its argument. These syntax rules are located inside of a languageâs grammar rule file.&lt;/p&gt;

&lt;p&gt;Again, the parser creates the Abstract Syntax Tree that the virtual machine compiles and interprets.&lt;/p&gt;

&lt;h3&gt;Tokenizer/Lexer&lt;/h3&gt;

&lt;p&gt;If youâre wondering how Ruby knows that &lt;code&gt;print&lt;/code&gt; is a separate element in the language from &lt;code&gt;&amp;#39;Hello, World&amp;#39;&lt;/code&gt;, then youâre understanding the function of the Lexer or Tokenizer. The Tokenizer scans your line of Ruby code, character-by-character and determines where the &amp;quot;words&amp;quot; of the language begin and end. The Tokenizer can tell the difference between a space separating words and a space separating a method name from its arguments.&lt;/p&gt;

&lt;p&gt;And thatâs the 10,000 foot lifecycle of a Ruby statement, as it goes from Tokenization to becoming machine code. If youâre looking for the microscopic explanation, Iâd recommend &lt;a href=&quot;http://www.nostarch.com/rum&quot;&gt;Ruby Under a Microscope&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;JavaScript&lt;/h2&gt;

&lt;h3&gt;Client-side&lt;/h3&gt;

&lt;p&gt;Most browsers implement &lt;a href=&quot;http://en.wikipedia.org/wiki/Just-in-time_compilation&quot;&gt;Just-In-Time (JIT) compiling&lt;/a&gt;. This means that the JavaScript code you write is compiled right before it gets executed by the virtual machine; though, in JavaScript, the interpreter is not referred to as a virtual machine, but as a JavaScript engine.&lt;/p&gt;

&lt;p&gt;V8 is the engine that interprets and executes JavaScript in the Chrome browser, Nitro is the engine for Safari, SpiderMonkey for Firefox, and Chakra on Internet Explorer. The efficiency with which a browser interprets JavaScript accounts for a substantial portion of its performance these days, especially as JavaScript-heavy, Single Page Applications become increasingly important.&lt;/p&gt;

&lt;h3&gt;Server-side&lt;/h3&gt;

&lt;p&gt;Node.js is the predominant framework for running JavaScript server-side. It is built on top of Googleâs V8 engine, which is a little confusing if youâve just read that V8 interprets JavaScript in the browser. In general terms, the JavaScript interpreter is extracted from Chrome, compiled on the server, and utilized by Node.js, allowing you to execute JavaScript outside of the browser.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Upon researching how a line of Ruby or JavaScript gets executed, you&amp;#39;ll quickly find that you can go down a rabbit hole. There are so many different implementations of Ruby, so many advancements in how code gets processed, and so much ambiguity in the terminology we use, that it can be quite challenging to form a mental model of what&amp;#39;s going on under the hood. That being said, a little patience goes a long way, and if you&amp;#39;re looking to dive into any one of the topics described above, I think you&amp;#39;ll be surprised at how readable much of the technical documentation is out there.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Automating Reefpoints</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/02/12/automating-reefpoints" />
    <id>https://dockyard.com/blog/2015/02/12/automating-reefpoints</id>
    <category term="automation" label="Automation"/>
    <published>2015-02-12 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>We used Travis-CI to automatically publish this blog</summary>
    <content type="html">&lt;p&gt;We have a healthy mix of developers and designers, plus a project manager and
office manager. This results in a group of people with varying degress of command line expertise.
To make it easier to write blog posts, &lt;a href=&quot;https://github.com/dockyard/reefpoints#the-github-web-interface-way&quot;&gt;I added instructions to create a blog
post using only GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This made it super easy for anyone to create a new blog post, have people
review it, but one piece was missing: making it easy for people to publish
their article once it was reviewed. Well, I solved that problem today with
&lt;a href=&quot;http://travis-ci.org&quot;&gt;Travis-CI&lt;/a&gt; and a little bit of bash script.&lt;/p&gt;

&lt;p&gt;The first step required was to script the publishing of our blog. We already
use &lt;a href=&quot;https://github.com/neo/middleman-gh-pages&quot;&gt;&lt;code&gt;middleman-gh-pages&lt;/code&gt;&lt;/a&gt;, which makes publishing as easy as &lt;code&gt;rake publish&lt;/code&gt;.
I created the following &lt;a href=&quot;https://github.com/dockyard/reefpoints/blob/master/travis_deploy.sh&quot;&gt;&lt;code&gt;travis_deploy.sh&lt;/code&gt;&lt;/a&gt; script:&lt;/p&gt;
&lt;div class=&quot;highlight sh &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;#!/usr/bin/env bash

set -e

git config --global user.email &amp;quot;socko@dockyard.com&amp;quot;
git config --global user.name &amp;quot;sockothesock&amp;quot;


# This specifies the user who is associated to the GH_TOKEN
USER=&amp;quot;sockothesock&amp;quot;

# sending output to /dev/null to prevent GH_TOKEN leak on error
git remote rm origin
git remote add origin https://${USER}:${GHTOKEN}@github.com/dockyard/reefpoints.git &amp;amp;&amp;gt; /dev/null

bundle exec rake publish

echo -e &amp;quot;Done\n&amp;quot;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;middleman-gh-pages&lt;/code&gt; is smart in that it figures out your GitHub remote based
on the origin, so what we did is update the origin to use a GitHUb OAuth token
that allows writing to public repos. We store the OAuth token in the
environment variable &lt;code&gt;GHTOKEN&lt;/code&gt;, which we encrypt in our &lt;a href=&quot;https://github.com/dockyard/reefpoints/blob/master/.travis.yml&quot;&gt;&lt;code&gt;travis.yml&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight yml &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;key&quot;&gt;language&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;ruby&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;sudo&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;cache&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;bundler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;rvm&lt;/span&gt;:
- &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;2.0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;branches&lt;/span&gt;:
  &lt;span class=&quot;key&quot;&gt;only&lt;/span&gt;:
  - &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;master&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;script&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;./travis_deploy.sh &amp;amp;&amp;gt; /dev/null&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;env&lt;/span&gt;:
  &lt;span class=&quot;key&quot;&gt;secure&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;eAyjmkDKLbXnGvC75KRNVLoAr6WE7ldT6JGOzOKOfQ9WxhEFgzAXoKZVO4mX4DfDfJbZbCyFmxKqALXGXjaBKwU2eQKeq1g4svBnxGPHmOKFMfVjkSCFag0bppE2JK9VXn70lVYFh8kJHavHgQ2pRYlSb78WfmUKbbB9PSH/rSE=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;notifications&lt;/span&gt;:
  &lt;span class=&quot;key&quot;&gt;slack&lt;/span&gt;:
    &lt;span class=&quot;key&quot;&gt;secure&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;o2ksyDNq6Ea2oHUbUpgICYHAUdZ0QgHSQNqgn/gginNyPYAd2MtS2h7iXVrzSgeXDSNi6WpAvAeOcUnzpA6h6oBkl0YvUTaXJs50IepWfAE4UZPwX9ZFfV8YiwnOCU9ByUTU2L9qeq83W3LuDYY7j6xZJjP5KMLC78TqTKy5pd8=&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I also added a Slack notification so that people can see when new blog posts
get published. The last thing I did was go into the Travis-CI setting and
turned off the option to build Pull Requests, as that would publish articles
before they were merged.  I accidentally leaked the OAuth Token in the Travis
logs (that&amp;#39;s why the &lt;code&gt;script&lt;/code&gt; step is redirecting output to &lt;code&gt;/dev/null&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In the end, it was really simple to automate the publication of our blog. It
has the added bonus of publishing corrections to the blog when anyone&amp;#39;s pull
request is merged.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Manage the conversation</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/02/11/managing-the-conversation" />
    <id>https://dockyard.com/blog/2015/02/11/managing-the-conversation</id>
    <category term="ux-design" label="Ux Design"/><category term="research" label="Research"/><category term="discovery" label="Discovery"/>
    <published>2015-02-11 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Learning to conduct user tests and interviews</summary>
    <content type="html">&lt;p&gt;One of my core UX design skills is finding information through user testing and interviews. What we gather will help us decide what to build, and how. This makes our ability to source qualitative information very important to the success of a product.&lt;/p&gt;

&lt;p&gt;A user interview is, at its essence, a closely managed conversation. It is my responsibility, as the designer, to manage it. The level of control required of the UX designer in this situation is unfamiliar, and can be stressful in the beginning. I think the reason for this initial discomfort is that we have little context for this managed type of conversation in our everyday life. Weâre used to conversations in which both parties share control over the direction and tone. Owning the conversation completely can feel rough and undemocratic. It takes skill and experience to do it while making the other party feel at ease.&lt;/p&gt;

&lt;p&gt;I want to share what I learned while conducting interviews and user tests at DockYard. I hope this will take some of the edge off the initial difficulty for others also learning this skill, and make it a more pleasant and productive time for all.&lt;/p&gt;

&lt;h2&gt;Lessons learned&lt;/h2&gt;

&lt;h3&gt;1. Prepare well&lt;/h3&gt;

&lt;p&gt;There is a lot of prep work involved, before the conversations can even start. Taking the time to do these steps properly allows me to get the most out of the time I spend with the interviewee.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Schedule the interviews. You may need to find suitable users yourself. Or, the client may help by putting you in touch with some preselected users to interview. Try not to schedule interviews back-to-back in case one takes a bit longer than expected.&lt;/li&gt;
&lt;li&gt;Arrange for the legal details. This could include notifying the interviewee of privacy arrangements, having them sign an NDA, or otherwise vetting the situation. Basically, you want to protect yourself, the person youâre interviewing, and the client by specifying how information is going to be used.&lt;/li&gt;
&lt;li&gt;Draft a sequence of questions that cover your desired information.&lt;/li&gt;
&lt;li&gt;Edit until questions sound polished and neutral (more on this to follow, in a separate post)&lt;/li&gt;
&lt;li&gt;Prepare a notebook, pen and a laptop.&lt;/li&gt;
&lt;li&gt;Print the questions so I can write notes in context and check off completed ones.&lt;/li&gt;
&lt;li&gt;Prepare backups and extra copies of any materials Iâm planning to use.&lt;/li&gt;
&lt;li&gt;Grab water and a snack! You donât want to take focus away from the interview by being too thirsty or hungry.&lt;/li&gt;
&lt;li&gt;If needed, also grab a timer and a sound recorder (your needs may vary)&lt;/li&gt;
&lt;li&gt;Triple-check the list of interviewees and their basic information. For example, phone interviews can happen over different time zones. Itâs nice to verify you&amp;#39;re not calling the person who kindly offered up their time at 6am.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;2. Establish context&lt;/h3&gt;

&lt;p&gt;Your interviewee should theoretically know who you are and what youâre talking about. After all, they agreed to the interview. However, it is always a good idea to confirm your assumptions. A brief introduction wonât hurt. For example, you could start with &lt;em&gt;âHi ____, thank you for taking time to do this! My name is ____, and my company was hired by ____ to improve their product. How familiar are you with the product?â&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;3. Direct the conversation&lt;/h3&gt;

&lt;p&gt;For a UX designer starting out, it may seem rude to redirect the conversation. Especially so if your interviewee is describing, with passion and detail, a subject they are an expert in. But don&amp;#39;t be afraid to redirect the conversation. You need to get to the specific questions you want answered (but of course be nice about it!). For example, to get back on track, you might say &lt;em&gt;âGreat - this extra information is very helpful, but Iâd like to get back to the original reason you started using ____?â&lt;/em&gt;  This acknowledges the value of their insight, then nudges them to answer your original question.&lt;/p&gt;

&lt;h3&gt;4. Go with the flow&lt;/h3&gt;

&lt;p&gt;At the start of the interview, there is a prepared, logical sequence of questions to ask. But in a conversation, one thing may lead naturally to another. If it makes sense to ask things out of order, itâs totally acceptable to do so. This is where a printed list of questions helps. Check them off as you go to make sure none remain unanswered.&lt;/p&gt;

&lt;h3&gt;5. Use teamwork&lt;/h3&gt;

&lt;p&gt;It is definitely easier to have a team of two handling the interview. This way, one person asks questions while the other focuses on capturing notes. Some notes may be of things like body language, expression, and movement - all important indicators of how a user may feel about the questions in addition to what they actually say. An experienced interviewer could probably handle both tasks with grace. As a beginner, it&amp;#39;s almost impossible. Try to do both at once, and you&amp;#39;ll either get awkward pauses as you write notes, or you&amp;#39;ll fail to record some of the valuable details.&lt;/p&gt;

&lt;h3&gt;6. Donât be afraid to clarify&lt;/h3&gt;

&lt;p&gt;Some interviews happen over the phone. The challenge here is that we lose most of the added information of body language and facial expression. This could be remedied with extra questions. For example, if I think the interviewee is referring to their laptop to answer something, I would literally ask that: &lt;em&gt;âIâm guessing youâre looking at the laptop screen for reference - is that correct?â&lt;/em&gt;  It is also important to be  attentive to the tone of voice so you can hear emotion, like hesitation.&lt;/p&gt;

&lt;p&gt;Another possible challenge in phone interviews is sound quality. Users may be on a shaky cell phone connection, or calling us via Skype. This can make their (and potentially your own) voice difficult to understand. It is tempting to dismiss the poor quality of sound and just omit details you canât quite hear. Make sure to always ask the interviewee to repeat or speak louder if you do not understand whatâs being said.&lt;/p&gt;

&lt;h2&gt;In conclusion&lt;/h2&gt;

&lt;p&gt;Conducting interviews caused me to cringe quite a few times. Am I doing it right? What does the interviewee think of me? Do I sound professional? Looking back, I can see how I and my colleagues got over our fears, and made significant improvements with just a few rounds of practice.&lt;/p&gt;

&lt;p&gt;Remember, both you and the interviewee are there because you want to improve some aspect of peopleâs lives through your work and their experience. Youâre on the same side, and you share this interest in the thing youâre discussing. Make the most of this interviewing situation, and you will see improved results each time.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember QUnit 0.2.x</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/02/06/ember-qunit-0-2" />
    <id>https://dockyard.com/blog/2015/02/06/ember-qunit-0-2</id>
    <category term="ember-cli" label="Ember-cli"/><category term="testing" label="Testing"/><category term="ember" label="Ember.js"/>
    <published>2015-02-06 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Robert Jackson</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/rwjblue/ember-qunit&quot;&gt;Ember QUnit&lt;/a&gt; 0.2.x has been released. It brings a whole bunch of bug fixes and some much needed cleanup, but there are a couple breaking changes also.&lt;/p&gt;

&lt;h2&gt;History of the changes&lt;/h2&gt;

&lt;p&gt;Ember QUnit started as a self contained library to make unit testing of Ember applications significantly easier. Ember QUnit proved that unit testing an Ember application could be very simple, and users of other testing frameworks wanted to join in the unit testing fun.  Unfortunately, the early code was fairly coupled to &lt;a href=&quot;http://qunitjs.com&quot;&gt;QUnit&lt;/a&gt; (the testing framework being used) so reusing the Ember unit testing helpers separate from QUnit was not possible.&lt;/p&gt;

&lt;p&gt;Ember QUnit 0.2.x is a complete organizational refactor to remove the Ember unit testing helpers (into the appropriately named &lt;a href=&quot;https://github.com/switchfly/ember-test-helpers&quot;&gt;ember-test-helpers&lt;/a&gt;) and keep the QUnit specific parts in Ember QUnit. The majority of this refactoring effort was done by &lt;a href=&quot;https://twitter.com/dgeb&quot;&gt;Dan Gebhardt&lt;/a&gt; and sponsored by the good folks at &lt;a href=&quot;http://www.switchfly.com&quot;&gt;SwitchFly&lt;/a&gt; (you can read their write-up of the work &lt;a href=&quot;http://blog.switchfly.com/2014/11/Refactoring-Ember-Testing-for-Mocha&quot;&gt;here&lt;/a&gt;). Out of this effort we have been able to create &lt;a href=&quot;https://github.com/switchfly/ember-mocha&quot;&gt;Ember Mocha&lt;/a&gt; which now has feature parity with Ember QUnit and is a truly first class Ember unit testing solution. Due to the usage of a general purpose underlying ember-test-helpers library, it should now be possible to create a nice wrapper around nearly any JS testing framework.&lt;/p&gt;

&lt;h2&gt;Notable Changes&lt;/h2&gt;

&lt;h3&gt;setup and teardown Deprecation&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;teardown&lt;/code&gt; are deprecated in favor of &lt;code&gt;beforeEach&lt;/code&gt; / &lt;code&gt;afterEach&lt;/code&gt;. This update was made to allow closer conformance to &lt;a href=&quot;http://qunitjs.com/upgrade-guide-2.x/&quot;&gt;QUnit 2.x&lt;/a&gt; concepts.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Refactor from (under 0.1.x):&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForComponent } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

moduleForComponent(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-sauce&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;AwesomeSauceComponent&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;setup&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() { },

  &lt;span class=&quot;function&quot;&gt;teardown&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() { }
});

&lt;span class=&quot;comment&quot;&gt;// To (under 0.2.x):&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForComponent } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

moduleForComponent(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-sauce&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;AwesomeSauceComponent&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;beforeEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() { },

  &lt;span class=&quot;function&quot;&gt;afterEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() { }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Global Assertion Deprecation&lt;/h3&gt;

&lt;p&gt;Usage of global assertions are deprecated and should be replaced with the &lt;code&gt;Assert&lt;/code&gt; argument to your test callbacks. This update was made to allow closer conformance to &lt;a href=&quot;http://qunitjs.com/upgrade-guide-2.x/&quot;&gt;QUnit 2.x&lt;/a&gt; concepts.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Refactor from (under 0.1.x):&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForComponent } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

moduleForComponent(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-sauce&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;implements awesomeness&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  equal(....);
  ok(....);
});

&lt;span class=&quot;comment&quot;&gt;// To (under 0.2.x):&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForComponent } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

moduleForComponent(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-sauce&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;implements awesomeness&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  assert.equal(....);
  assert.ok(....);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Arguments to setup / teardown / beforeEach / afterEach&lt;/h3&gt;

&lt;p&gt;In prior versions of Ember QUnit, the &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;teardown&lt;/code&gt; hooks were called with a single argument: the container. In Ember QUnit 0.2 this argument is no longer present.&lt;/p&gt;

&lt;p&gt;Note: usage of &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;teardown&lt;/code&gt; are deprecated, you should use &lt;code&gt;beforeEach&lt;/code&gt; and &lt;code&gt;afterEach&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Refactor from (under 0.1.x):&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForComponent } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

moduleForComponent(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-sauce&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;AwesomeSauceComponent&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;setup&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(container) {
    &lt;span class=&quot;comment&quot;&gt;/* do stuff */&lt;/span&gt;
  },

  &lt;span class=&quot;function&quot;&gt;teardown&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(container) {
    &lt;span class=&quot;comment&quot;&gt;/* do stuff */&lt;/span&gt;
  }
});

&lt;span class=&quot;comment&quot;&gt;// To (under 0.2.x):&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForComponent } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

moduleForComponent(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-sauce&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;beforeEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; container = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.container;

    &lt;span class=&quot;comment&quot;&gt;/* do stuff */&lt;/span&gt;
  },

  &lt;span class=&quot;function&quot;&gt;afterEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; container = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.container;

    &lt;span class=&quot;comment&quot;&gt;/* do stuff */&lt;/span&gt;
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Deprecated this.append in Component tests&lt;/h3&gt;

&lt;p&gt;In a component test you would previously call &lt;code&gt;this.append()&lt;/code&gt; to append your component into the DOM.  This was somewhat confusing, and took some explaining when teaching to newcomers, so it has been replaced with &lt;code&gt;this.render()&lt;/code&gt; which fits much better in our Ember mindset.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Refactor from (under 0.1.x):&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForComponent } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

moduleForComponent(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-sauce&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;implements awesomeness&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; component = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.subject();

  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.append();

  equal(component.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;().text(), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;WHOAA!! AWESOME!!!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});

&lt;span class=&quot;comment&quot;&gt;// To (under 0.2.x):&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForComponent } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

moduleForComponent(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;awesome-sauce&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;implements awesomeness&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; component = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.subject();

  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.render();

  assert.equal(component.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;().text(), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;WHOAA!! AWESOME!!!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Ordering of afterEach / teardown Callback&lt;/h3&gt;

&lt;p&gt;In Ember QUnit 0.1.x, the &lt;code&gt;teardown&lt;/code&gt; callback was called &lt;em&gt;after&lt;/em&gt; all internal cleanup was finished (like clearing the container, removing any views from the DOM, etc).  In Ember QUnit 0.2.x &lt;code&gt;afterEach&lt;/code&gt; / &lt;code&gt;teardown&lt;/code&gt; is called before the internal hooks.&lt;/p&gt;

&lt;h3&gt;Build Changes&lt;/h3&gt;

&lt;p&gt;There are a few build related changes with Ember QUnit 0.2.x:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build output is removed from the main repo, and now is maintained at &lt;a href=&quot;https://github.com/rwjblue/ember-qunit-builds&quot;&gt;ember-qunit-builds&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The output file locations are no longer nested in &lt;code&gt;dist/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;CJS and AMD output is no longer generated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;&lt;a href=&quot;https://github.com/ember-cli/ember-cli-qunit&quot;&gt;ember-cli-qunit&lt;/a&gt; Version&lt;/h3&gt;

&lt;p&gt;If you are using Ember CLI, you should update to &lt;a href=&quot;https://github.com/ember-cli/ember-cli-qunit&quot;&gt;ember-cli-qunit&lt;/a&gt; version 0.3.7.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;Please file issues &lt;a href=&quot;https://github.com/rwjblue/ember-qunit/issues&quot;&gt;ember-qunit issues&lt;/a&gt; if you come across anything that isn&amp;#39;t listed here.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Vim: Jump, Jump, Jump!</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/02/04/vim-jump-jump-jump" />
    <id>https://dockyard.com/blog/2015/02/04/vim-jump-jump-jump</id>
    <category term="vim" label="Vim"/><category term="workflow" label="Workflow"/>
    <published>2015-02-04 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>Kris Kross&#39; favorite Vim feature</summary>
    <content type="html">&lt;h1&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=010KyIQjkTk&quot; target=&quot;_blank&quot;&gt;Jump, Jump, Jump!&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;In the last Vim-related post, we
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/04/10/vim-on-your-mark.html&quot;&gt;discussed &lt;strong&gt;mark&lt;/strong&gt; motion&lt;/a&gt;,
and today, we&amp;#39;re going to cover another type of navigation: &lt;strong&gt;jump&lt;/strong&gt; motion.&lt;/p&gt;

&lt;p&gt;The main benefit of jump motion is its speed; it allows us to quickly traverse through the current file
open or previously visited files.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s briefly cover some of the most familiar ones.&lt;/p&gt;

&lt;h2&gt;File Jumps&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;File jumps&lt;/em&gt; will navigate you to a location within the current file, regardless if that
location is seen or not seen within the window.&lt;/p&gt;

&lt;h3&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Xz-UvQYAmbg&quot; target=&quot;_blank&quot;&gt;Ain&amp;#39;t no Mountain high enough, ain&amp;#39;t no valley low enough...&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;gg&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Will take you to the &lt;em&gt;top&lt;/em&gt; of the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;G&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Will take you to the &lt;em&gt;bottom&lt;/em&gt; of the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Sentences and Paragraphs&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move a &lt;em&gt;sentence backwards&lt;/em&gt;, can take a prefix argument.

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;5(&lt;/strong&gt; - Navigates you 5 sentences backwards.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;e Move a &lt;em&gt;sentence forward&lt;/em&gt;, can take a prefix argument.
  * &lt;strong&gt;10)&lt;/strong&gt; - Navigates you 10 sentences forwards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;{&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move a &lt;em&gt;paragraph backward&lt;/em&gt;, can take a prefix argument.

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;5{&lt;/strong&gt; - Navigates you 5 paragraphs backwards.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;}&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move a &lt;em&gt;paragraph forward&lt;/em&gt;, can take a prefix argument.

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;5}&lt;/strong&gt; - Navigates you 5 paragraphs forwards.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=EDNzQ3CXspU&quot; target=&quot;_blank&quot;&gt;Search and Destroy&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allows you to search &lt;em&gt;forwards&lt;/em&gt; for a desired pattern within the file.

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;/fishsticks&lt;/strong&gt; - Searches for all occurences of &lt;code&gt;fishsticks&lt;/code&gt; ahead of your current cursor.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allows you to search &lt;em&gt;backwards&lt;/em&gt; for a desired pattern within the file.

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;?catdog&lt;/strong&gt; - Searches for all occurences of &lt;code&gt;catdog&lt;/code&gt; behind your current cursor.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;n&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeats the last &lt;strong&gt;/&lt;/strong&gt; or &lt;strong&gt;?&lt;/strong&gt; search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;N&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeats the last &lt;strong&gt;/&lt;/strong&gt; or &lt;strong&gt;?&lt;/strong&gt; search in the &lt;em&gt;opposite&lt;/em&gt; direction.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Window Jumps&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Window&lt;/em&gt; jumps allow you to move within the current scope of the window or viewport.&lt;/p&gt;

&lt;h3&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=JECF2EB3LXU&quot; target=&quot;_blank&quot;&gt;High, Middle, and Low&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;H&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jumps your cursor to the &lt;strong&gt;highest&lt;/strong&gt; line of the window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;M&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jumps your cursor to the &lt;strong&gt;middle&lt;/strong&gt; line of the window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;L&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jumps your cursor to the &lt;strong&gt;lowest&lt;/strong&gt; line of the window.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;System Wide Jumps&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;System&lt;/em&gt; jumps are special; they have the ability to take us to any previously visited file,
regardless if those files are or are not within the same directory.&lt;/p&gt;

&lt;p&gt;This is where jump motion really shines!&lt;/p&gt;

&lt;h3&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=KZaz7OqyTHQ&quot; target=&quot;_blank&quot;&gt;Jump Around&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Give these next commands a try:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CTRL-O&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jump to our previous position.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CTRL-I&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jump to our next postion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By pressing these commands repeatedly, you&amp;#39;ll see that you are traversing through
your recently visited files.&lt;/p&gt;

&lt;h3&gt;Jump list&lt;/h3&gt;

&lt;p&gt;Our recent jumps are stored on our &lt;em&gt;jump&lt;/em&gt; list. We can view all the jumps through Vim&amp;#39;s
command-line mode. There are three ways to open up the jump list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:jumps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:jump&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:ju&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opens up the jump list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/mFc1cHz.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Above is an example of a jump list. There are four columns: &lt;em&gt;jump&lt;/em&gt;, &lt;em&gt;line&lt;/em&gt;, &lt;em&gt;col&lt;/em&gt; and &lt;em&gt;file/text&lt;/em&gt;.
The numbers underneath the &lt;em&gt;jump&lt;/em&gt; column are used to prefix our jump command, &lt;strong&gt;CTRL-O&lt;/strong&gt; and &lt;strong&gt;CTRL-I&lt;/strong&gt;.
We are also given the position of our cursor from the  &lt;em&gt;line&lt;/em&gt; and &lt;em&gt;col&lt;/em&gt;umn columns. Lastly, the
&lt;em&gt;file/text&lt;/em&gt; column, gives us either the file path or, if the jump is located in our currently opened file,
the line of text.&lt;/p&gt;

&lt;p&gt;Using our example jump list, if we want to jump to the &lt;code&gt;4&lt;/code&gt;th jump, located within &lt;code&gt;~/dir2/file.md&lt;/code&gt;, we&amp;#39;d
prefix our previous jump command with the number &lt;strong&gt;4&lt;/strong&gt;, i.e. &lt;strong&gt;4CTRL-O&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next if we want to get back to our previous position, the line
&lt;code&gt;This is another sentence!&lt;/code&gt; we can cycle back to it with a couple of &lt;strong&gt;CTRL-I&lt;/strong&gt;s. Cool!&lt;/p&gt;

&lt;p&gt;I find that &lt;em&gt;jump&lt;/em&gt; motion complements &lt;em&gt;mark&lt;/em&gt; motion really well. By setting multiple marks in the current file,
and flying to different files with jumps, my workflow has greatly improved.&lt;/p&gt;

&lt;p&gt;Hope you give &lt;em&gt;jump&lt;/em&gt; motion a try!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Debugging a Broccoli Tree</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/02/02/debugging-a-broccoli-tree" />
    <id>https://dockyard.com/blog/2015/02/02/debugging-a-broccoli-tree</id>
    <category term="broccoli" label="Broccoli"/>
    <published>2015-02-02 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Robert Jackson</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/broccolijs/broccoli&quot;&gt;Broccoli&lt;/a&gt; is a great tool for building up assets gradually through a list of changing steps. Unfortunately, when things go wrong in one of your steps it is often very difficult to figure out what is happening at each stage.&lt;/p&gt;

&lt;p&gt;Here is where &lt;a href=&quot;https://github.com/stefanpenner/broccoli-stew&quot;&gt;broccoli-stew&lt;/a&gt; comes in, it is a Broccoli utility library that contains a number of super useful plugins with a &lt;a href=&quot;https://en.wikipedia.org/wiki/POSIX&quot;&gt;posix&lt;/a&gt; flair to them. Tools like &lt;code&gt;mv&lt;/code&gt;, &lt;code&gt;rename&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, and &lt;code&gt;debug&lt;/code&gt; make it much easier to reason about your Broccoli build.&lt;/p&gt;

&lt;p&gt;And thanks to the &lt;code&gt;debug&lt;/code&gt; and &lt;code&gt;log&lt;/code&gt; plugins it has become &lt;strong&gt;massively&lt;/strong&gt; easier to log the contents of each tree, or get an extra copy to poke at manually.&lt;/p&gt;

&lt;h3&gt;Initial Brocfile.js&lt;/h3&gt;

&lt;p&gt;Lets assume you have the following &lt;code&gt;Brocfile.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Brocfile.js&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Funnel = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-funnel&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; ES2015 = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-es6modules&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; log = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-stew&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).log;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; app = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Funnel(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;key&quot;&gt;destDir&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;my-app-name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
});

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; transpiledTree = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; ES2015(app);

module.exports = transpiledTree;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The goal of the Brocfile.js listed above is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grab all files in &lt;code&gt;app/&lt;/code&gt; and its subdirectories&lt;/li&gt;
&lt;li&gt;&amp;quot;move&amp;quot; those files to &lt;code&gt;my-app-name/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;transpile those files from &lt;a href=&quot;http://webreflection.blogspot.co.uk/2015/01/javascript-and-living-ecmascript.html&quot;&gt;ES2015&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So far this seems pretty easy, but what if your resulting output didn&amp;#39;t contain the files you expected?  How would you track that down?&lt;/p&gt;

&lt;h3&gt;Log Tree&lt;/h3&gt;

&lt;p&gt;You can log the files in a tree using &lt;code&gt;broccoli-stew&lt;/code&gt;&amp;#39;s &lt;code&gt;log&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Brocfile.js&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Funnel = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-funnel&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; ES2015 = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-es6modules&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; log = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-stew&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).log;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; app = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Funnel(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;key&quot;&gt;destDir&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;my-app-name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; loggedApp = log(app, { &lt;span class=&quot;key&quot;&gt;output&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;label&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;my-app-name tree&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; });

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; transpiledTree = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; ES2015(loggedApp);

module.exports = transpiledTree;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Using &lt;code&gt;log&lt;/code&gt; like this will list out the files that are present just after the &lt;code&gt;Funnel&lt;/code&gt; step.  It might output something like the following:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my-app-name tree
âââ my-app-name/
   âââ my-app-name/cat.js
   âââ my-app-name/dog.js
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is super helpful to see that the right files are selected, but what if you are seeing the right files but the contents were not right?&lt;/p&gt;

&lt;h3&gt;Debug Tree&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;broccoli-stew&lt;/code&gt;&amp;#39;s &lt;code&gt;debug&lt;/code&gt; you can have a duplicate copy of the tree generated into the root of the project so you can inspect it later (it will not get cleaned up at the end of the build like the temp folders do).&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Brocfile.js&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Funnel = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-funnel&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; ES2015 = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-es6modules&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; debug = require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;broccoli-stew&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).debug;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; app = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Funnel(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;key&quot;&gt;destDir&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;my-app-name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; debugApp = debug(app, { &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;my-app-name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; });

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; transpiledTree = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; ES2015(debugApp);

module.exports = transpiledTree;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;debug&lt;/code&gt; plugin as used above will create a folder on disk at &lt;code&gt;DEBUG-my-app-name&lt;/code&gt; in the root of your project with the full contents of the &lt;code&gt;app&lt;/code&gt; tree when it was called. You can review this folder&amp;#39;s contents at your leisure without worrying about the Broccoli server calling cleanup and deleting the directory.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;broccoli-stew&lt;/code&gt; to debug a Broccoli pipeline is absolutely awesome, and makes getting a project using Broccoli much easier.  Thanks to &lt;a href=&quot;https://twitter.com/stefanpenner&quot;&gt;@stefanpenner&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/chadhietala&quot;&gt;@chadhietala&lt;/a&gt; for pushing things forward!&lt;/p&gt;

&lt;p&gt;If you&amp;#39;d like to checkout and play with the &lt;code&gt;Brocfile.js&lt;/code&gt; above, you can do the normal &lt;code&gt;git clone&lt;/code&gt; and &lt;code&gt;npm install&lt;/code&gt; song and dance with &lt;a href=&quot;https://github.com/rwjblue/debugging-broccoli&quot;&gt;https://github.com/rwjblue/debugging-broccoli&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Why I&#39;m disappointed in React Native</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/30/why-i-am-disappointed-in-react-native" />
    <id>https://dockyard.com/blog/2015/01/30/why-i-am-disappointed-in-react-native</id>
    <category term="opinion" label="Opinion"/><category term="javascript" label="JavaScript"/>
    <published>2015-01-30 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;This week at React.js Conf 2015 React Native was introduced. You can see
the two most important videos here:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot;
src=&quot;https://www.youtube.com/embed/KVZ-P-ZI6W4&quot; frameborder=&quot;0&quot;
allowfullscreen&gt;&lt;/iframe&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot;
src=&quot;https://www.youtube.com/embed/7rDsRXj9-cU&quot; frameborder=&quot;0&quot;
allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;The TLDR is that Facebook has developed a view layer for React that can
be used within native mobile apps. Within this context React&amp;#39;s templates
can call native components (and views) as if you were referring to normal
HTML elements. Furthermore a JavaScript layer has been introduced to the
native layer that runs the React applications, this means that you can
debug your React Native applications in Chrome Web Tools while it runs
on an iOS device.&lt;/p&gt;

&lt;p&gt;This is &lt;em&gt;amazing&lt;/em&gt; technology and I don&amp;#39;t think anyone was expecting
this. As an Ember developer I&amp;#39;m jealous. After some reflection I
realized I was also incredibly disappointed in Facebook for heading in
this direction.&lt;/p&gt;

&lt;h3&gt;We are (supposed to be) all in this together&lt;/h3&gt;

&lt;p&gt;The web development Holy Grail right now is to compete directly with (perhaps
someday replace) native mobile applications. With React Native the web
has lost a huge partner in Facebook for helping make this a reality.
What incentive does Facebook have for pushing forward mobile web now
that they can just produce native applications with web technology? What
incentive do the existing React developers (and the large number of
developers that will move to React in the near future) have for building
and proving out mobile web use-cases with React Native? &lt;strong&gt;None&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;We are getting close&lt;/h3&gt;

&lt;p&gt;This year saw significant improvements in mobile web. We are so close.
Check out this video from Google showing off the potential of mobile
web:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot;
src=&quot;https://www.youtube.com/embed/v0xRTEf-ytE&quot; frameborder=&quot;0&quot;
allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;No longer is mobile web a matter of &lt;em&gt;if&lt;/em&gt; but a matter of &lt;em&gt;when&lt;/em&gt;.
However, with Facebook effectively taking themselves out of the
conversation we&amp;#39;ve lost one of the best use-cases and the largest voices
with one of the most popular JavaScript frameworks.&lt;/p&gt;

&lt;p&gt;Mobile web is a point of friction currently, and that friction existing
is good because it will drive people and companies to pursue solutions
to the problem. React Native is a work-around for mobile web. Some will
think of it as a &amp;quot;best of both worlds&amp;quot; and perhaps they are correct. But
the problem of mobile web will continue to exist.&lt;/p&gt;

&lt;h3&gt;Business needs trump ideological ones&lt;/h3&gt;

&lt;p&gt;Of course Facebook should do what is in its own best interest. &lt;a href=&quot;http://techcrunch.com/2012/09/11/mark-zuckerberg-our-biggest-mistake-with-mobile-was-betting-too-much-on-html5/&quot;&gt;In 2012
Mark Zuckerberg said that Facebook bet too heavily on
HTML5&lt;/a&gt;.
He was correct then and he is correct now: mobile web feels like shit
when compared to native. The User Experience is the primary concern for
any product company. This, however, should not stop us from persuing
mobile web and pushing the technology forward. I just hope that React
Native doesn&amp;#39;t impede that progress in any way.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Empowering through Design</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/30/empowering-through-design" />
    <id>https://dockyard.com/blog/2015/01/30/empowering-through-design</id>
    <category term="design" label="Design"/><category term="interaction" label="Interaction"/><category term="user-experience" label="User Experience"/><category term="native-web" label="Native Web"/>
    <published>2015-01-30 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Ashley Treni</name></author>
    <summary>The UX benefits of Single Page Web Apps</summary>
    <content type="html">&lt;p&gt;There has been some debate in the development community between the &lt;a href=&quot;https://medium.com/@cramforce/tradeoffs-in-server-side-and-client-side-rendering-14dad8d4ff8b&quot;&gt;&amp;quot;tradeoffs in server side and client side rendering.&amp;quot;&lt;/a&gt; As a UX designer working at an Ember shop that focuses on rich client experiences, I&amp;#39;ve observed the benefits of single page web applications, from a design perspective.&lt;/p&gt;

&lt;p&gt;The best kind of user interface is one where the system remains transparent, and moves the user fluently through relevant prompts to accomplish the task at hand. That experience can only be as good as the tools we have to shape and elevate that participation. At DockYard, we design and develop single page web apps using Ember as our client-side framework, because it allows for greater clarity of interaction, while keeping the technology transparent.&lt;/p&gt;

&lt;p&gt;A single page web app is a webpage that can update contents within the page without refreshing the entire browser window. Because the server doesn&amp;#39;t dictate the display, the &amp;quot;client,&amp;quot; or browser, determines how to represent it. Only the data associated with the selection is changed to reflect the action. &lt;/p&gt;

&lt;p&gt;You can imagine how beneficial that real time feedback is on the user side of the experience. Whether aware of it or not, this creates a more immersive experience, and enables the user to better grasp the information by directing attention to content. There is more opportunity to nest information which alleviates information overload, and animation simplifies complexity while still engaging the user. &lt;/p&gt;

&lt;p&gt;To do this well, good information architecture and content organization are imperative. Functionality and interaction must be part of the architecture, but not interrupt the flow and navigation. The visual design and communication must be clear and directive. The design supports self directed navigation and the process is not disrupted by the reload of a page. Creating this kind of real time response in the browser is the result of better, faster performance, bringing us closer to a native feel from the web.&lt;/p&gt;

&lt;iframe src=&quot;//player.vimeo.com/video/118249906&quot; width=&quot;500&quot; height=&quot;452&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;&lt;a href=&quot;https://learnivore.com/&quot;&gt;Learnivore&lt;/a&gt; is a website that connects teachers and students searching for instruction across many disciplines. The search page is one of the largest hubs in the Learnivore experience. This &lt;a href=&quot;http://reefpoints.dockyard.com/2015/01/07/complex-search-pages-feel-better-in-ember.html&quot;&gt;&amp;quot;complex search&amp;quot;&lt;/a&gt; filters by type of instruction, location, rate, price, qualifications, and more. The results change dynamically, reflecting the filter selection, as demonstrated in the video above.&lt;/p&gt;

&lt;p&gt;Good design empowers the user to make the choices they need to accomplish their goals. It promotes communication and supports informed decision making through real time response. The single page web app model and the technologies to create and innovate with it are at the forefront of mobile and web design and development. It is a technology that not only provides opportunities for creativity and innovation for designers and developers alike, it constructs a more informative and cooperative experience for our users.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Bubbling actions through components</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/28/bubbling-actions-through-components" />
    <id>https://dockyard.com/blog/2015/01/28/bubbling-actions-through-components</id>
    <category term="ember" label="Ember.js"/>
    <published>2015-01-28 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Let your actions be handled in your controllers and routes</summary>
    <content type="html">&lt;p&gt;If you&amp;#39;re building components for re-use, you&amp;#39;re likely to run into the
following problem. Say you built a form component, and you also built some type
of custom button component. You want the action triggered by the button to be
handled in your controller or route. If you try to bind the action of that
inner button, it will be captured by the component, not the controller. The
issue is that components swallow actions that are triggered within them; they
will not escape the component unless we punch a hole for them to bubble up.&lt;/p&gt;

&lt;p&gt;You need to capture the action of the inner components and fire off new actions
from the parent component. In the example below, the button is in a component
that is inside of another component. The controller has an action to increment
the counter.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;jsbin-embed&quot; href=&quot;http://jsbin.com/suvat/4/embed?output&quot;&gt;Ember Starter Kit&lt;/a&gt;&lt;script src=&quot;http://static.jsbin.com/js/embed.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Our components&amp;#39; templates are super simple:&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{{! index.hbs}}
  {{pressCount}} Button presses
  {{button-wrapper action=&amp;quot;buttonClick&amp;quot;}}

{{! components/button-wrapper.hbs}}
  &amp;lt;h2&amp;gt;Button Wrapper&amp;lt;/h2&amp;gt;
  {{press-button action=&amp;quot;buttonClick&amp;quot;}}

{{! components/press-button.hbs}}
  &amp;lt;button {{action &amp;quot;buttonClick&amp;quot;}}&amp;gt;My Button&amp;lt;/button&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice we bind to the action of the &lt;code&gt;press-button&lt;/code&gt; component in our
&lt;code&gt;button-wrapper&lt;/code&gt; component, and in our &lt;code&gt;index&lt;/code&gt; template, we bind to the action
of the &lt;code&gt;button-wrapper&lt;/code&gt;. This alone doesn&amp;#39;t work; we need to send actions from
each component when they receive actions from the underlying component.&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;press-button&lt;/code&gt; component, we send an action when the button is clicked:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.PressButtonComponent = Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;classNames&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;press-button&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    &lt;span class=&quot;function&quot;&gt;buttonClick&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.sendAction();
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Our &lt;code&gt;button-wrapper&lt;/code&gt; receives the action from the &lt;code&gt;press-button&lt;/code&gt; component and
fires its own action:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.ButtonWrapperComponent = Ember.Component.extend({
  &lt;span class=&quot;key&quot;&gt;classNames&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;button-wrapper&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    &lt;span class=&quot;function&quot;&gt;buttonClick&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.sendAction();
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And our index controller receives that action from &lt;code&gt;button-wrapper&lt;/code&gt; and
increments the &lt;code&gt;pressCount&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.IndexController = Ember.Controller.extend({
  &lt;span class=&quot;key&quot;&gt;pressCount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;,

  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    &lt;span class=&quot;function&quot;&gt;buttonClick&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.incrementProperty(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pressCount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;It&amp;#39;s pretty easy, yet tedious to wire up an action from a component within a
component. You can trigger actions multiple levels above your initial action,
and even mutate the action&amp;#39;s arguments on the way up. Maybe the model that
triggered the initial action should be put into some type of intermediate
state. Maybe you want to normalize several different actions that are bubbling
up through certain components. Since you need to manually bubble these
actions up, we can manipulate them at each level that the bubbling occurs. It&amp;#39;s
somewhat trivial to handle, you just have to be aware of the work needed to
tie all your pieces together.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Estimation Buyers Guide</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/28/estimation-buyers-guide" />
    <id>https://dockyard.com/blog/2015/01/28/estimation-buyers-guide</id>
    <category term="project-management" label="Project Management"/>
    <published>2015-01-28 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Jon Lacks</name></author>
    <summary>Buyer beware of estimates without understanding how it was derived</summary>
    <content type="html">&lt;p&gt;As a Project Manager, I have seen estimates in all forms - points, days, months, hours, mario coins, etc. Many say estimates in Software development are garbage and significant margin of error should be the expected norm. I believe this perspective to be true if estimation is conducted in a vacuum vs. as a means to have a conversation with prospective clients about what it is going to take to achieve their vision.&lt;/p&gt;

&lt;p&gt;While estimation provides financial insight into a project, it also provides the project team with a point of reference when it comes to establishing schedules and conducting impact analysis when something needs to change (which is inevitable). As a project manager, a solid process by which we establish an estimate allows me to best serve the client and team.&lt;/p&gt;

&lt;p&gt;I would question any firm who claims to offer a high confidence estimate to a prospective client without spending time mapping out the direction an application/product may take on paper. I am not talking about writing a 50 page requirements document (which I once did on a project 10 years before I knew any better).  I am talking about getting the âsupporting&amp;quot; cast the context they need to provide an informed perspective on the complexity associated with building the application.  This complexity spans design, engineering, quality and any other overhead associated with a project. &lt;/p&gt;

&lt;p&gt;Let me paint this picture for you. Client X wants to build out a new application. The team to build said application provides client X with an estimate based off of a couple pre-sales meetings. Cost is negotiated until everyone around the table is happy with the economics and then the project is handed over to the project team and they are told to build âthisâ application in âthisâ amount of time. Client X is doomed regardless of whether or not that application is handed over in the agreed amount of time. Hereâs why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The team has no context - Therefore, they are going to spend the first weeks of development getting up to speed as opposed to delivering working features putting the schedule behind right out of the gate&lt;/li&gt;
&lt;li&gt;The team does not &amp;quot;own&amp;quot; the estimate -  Someone else provided it on their behalf (who wants to be responsible for something they donât own?)&lt;/li&gt;
&lt;li&gt;Unexpected risks and complexity will (not âmayâ) put schedule at risk&lt;/li&gt;
&lt;li&gt;Quality will (not âmay&amp;quot;) suffer because the team will attempt to meet the date commitment at the expense of quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To avoid this at DockYard, we use a tool called Discovery. This is an intensive time-boxed exploration of a clientâs business objectives, market and user needs, as well as technological possibilities. These inputs translate into wireframes and those wireframes translate into an estimable breakdown of deliverables that provides a platform to discuss scope, schedule and cost with our client. Our Discovery phase is cross-functional where we have designers and developers working hand in hand to understand the direction a client wants to go. We iterate on design concepts, we discuss technical direction and potential complexities, we map out scope in a way that allows clients to make decisions which may adjust cost and schedule up or down.   While this Discovery phase might feel like a tough nut to crack, it typically results in lower overall project cost, higher quality and better probability of staying on budget/schedule.&lt;/p&gt;

&lt;p&gt;A recent post by our own Mike Dupuis speaks to the value engineers can add to the âDiscoveryâ phase of a project resulting in savings later in the project lifecycle-  &lt;a href=&quot;http://reefpoints.dockyard.com/2014/09/12/features-as-business-objectives.html&quot;&gt;Features as Business Objectives&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whether you love them or hate them, estimates are here to stay in a client services context.  Therefore, instead of grumbling about them - make sure you&amp;#39;re using estimation as more than just a number but a means to have a conversation. Buyer beware of anyone who slaps an estimate on the table without providing you an explanation of how that estimate was derived.  &lt;/p&gt;

&lt;p&gt;âLuck is what happens when preparation meets opportunityâ - Well said by someone much more insightful than I!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Is your homepage as good as your door sign?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/20/is-your-homepage-as-good-as-your-door-sign" />
    <id>https://dockyard.com/blog/2015/01/20/is-your-homepage-as-good-as-your-door-sign</id>
    <category term="design" label="Design"/><category term="observations" label="Observations"/><category term="user-experience" label="User Experience"/>
    <published>2015-01-20 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Ask good questions to solve for real user goals</summary>
    <content type="html">&lt;p&gt;Today is a federal holiday, and a day off for us at DockYard. On days like these, when I do not travel, I often go to the local library.&lt;/p&gt;

&lt;p&gt;Today gave me the perfect opportunity to see how easy it would be to find a specific bit of information (&lt;em&gt;is the library open today?&lt;/em&gt;) on a library website.&lt;/p&gt;

&lt;p&gt;Like many government and community organizations, libraries are easy targets for ridicule when it comes to web design. Look at the outdated styles their site uses! How crowded it is! The HTML tables used for layout! The multi-colored announcements âdesignedâ in Word!Â &lt;/p&gt;

&lt;p&gt;What I am looking for today is something else: I want to judge the achievability of a specific task regardless of the presentation. Presentation (layout, hierarchy, and just plain good design) affects a userâs ability to achieve her goals, no doubt. I just want to start with the goals, and a specific measurement, rather than starting with the common pitfall of visual designers like myself: noticing the surface details that seem broken rather than the process behind them.&lt;/p&gt;

&lt;p&gt;So, hereâs my experiment:&lt;/p&gt;

&lt;h2&gt;Find out if the library is open today.&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;With a few considerations.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It may be &lt;strong&gt;self evident&lt;/strong&gt; that a library is closed on a government holiday. It was not to me. I assume that most casual users have a vague suspicion that it may be closed, and would seek confirmation via the website.&lt;/p&gt;

&lt;p&gt;I narrowed my search to just the homepage for this exercise, expecting to find the equivalent of a physical âSorry, closed today!â door sign. And while many libraries provided the same information on Twitter or Facebook, it would be prohibitive to compare all these resources for this quick study.&lt;/p&gt;

&lt;p&gt;I saw most of these homepages for the first time today. A regular user of the local library may notice things differently than a new user, so for example the âCLOSEDâ text announcement that replaces a daily schedule of events, might stand out more for them.&lt;/p&gt;

&lt;p&gt;I looked for three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; was the holiday at all on the homepage, Â &lt;/li&gt;
&lt;li&gt;was it clear, andÂ &lt;/li&gt;
&lt;li&gt;was it obvious?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I got about halfway down the alphabetized list of Minuteman Library Network locations, and consider this to be a useful and fair sample for my purpose.&lt;/p&gt;

&lt;p&gt;Letâs roll:&lt;/p&gt;

&lt;h3&gt;1. Acton&lt;/h3&gt;

&lt;h2&gt;3/3!&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/ebDk2UJ.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;The site is visually appealing and clear at the same time. I immediately got an answer to my question. Success!&lt;/p&gt;

&lt;h3&gt;2. Arlington (Robbins Library)&lt;/h3&gt;

&lt;h2&gt;0/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/CpqOqdR.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Hours are clearly listed, but the holiday is not. Based on this page, I would assume it is open todayâââin fact, the clear listing of hours reinforces my wrong assumption. To see the holiday announcement, I would need to know to visit the Calendar. A shame, because the site looks quite polished to me and was likely re-designed fairly recently (guessing 2013, from its footer). An investment in a bit of user testing and research would have likely fixed this.&lt;/p&gt;

&lt;h3&gt;3. Ashland&lt;/h3&gt;

&lt;h2&gt;Huh? 0.5/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/yQ2dOww.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;While there is no indication of library closure today, the Townhall is clearly  closed. As a local, I might know what that means for my library trip, so I gave 0.5 points for at least mentioning the holiday exists.&lt;/p&gt;

&lt;h3&gt;4. Bedford&lt;/h3&gt;

&lt;h2&gt;0/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/XhAfaNt.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Todayâs closure is not mentioned anywhere. Neither are the regular hours. I would look  either in About Us, or (eventually) see a link for Hours &amp;amp; Directions close to the top right.&lt;/p&gt;

&lt;h3&gt;5. Belmont&lt;/h3&gt;

&lt;h2&gt;3/3!&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/inJbhUs.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;The site doesnât look like much, but it accomplishes my goal today perfectly. The library is clearly closed.&lt;/p&gt;

&lt;h3&gt;6. Brookline&lt;/h3&gt;

&lt;h2&gt;3/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/jpBCY9k.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;This library goes beyond my expectations by clearly listing not only todayâs closure, but the entire holiday weekend for all three of its locations. The âClosedâ notice is clear and immediately jumps to my attention. While there is no âclosed TODAYâ notice, I found this more detailed listing works just as well.&lt;/p&gt;

&lt;h3&gt;7. Cambridge&lt;/h3&gt;

&lt;h2&gt;0/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/QVg8HQO.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;This library was a particular disappointment, because I have used it many times and the collection and its building are delightful. I am assuming it is one of the better funded libraries, given its location in direct proximity to Harvard. While the amount of content this page needs to show may be far greater than what a smaller local library deals with, this is no excuse for making things difficult to find. I get the feeling that the structure of the site is based on internal objectives, rather than user goals.Â &lt;/p&gt;

&lt;p&gt;Hereâs where todayâs closure information is, in fact, located:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/W4eopoE.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;I would have to do this:
- âfind library hoursâ on the homepage
- select âholidaysâ among eleven listings
- see on the list that today, January 19th, is a holiday&lt;/p&gt;

&lt;h3&gt;8. Concord&lt;/h3&gt;

&lt;h2&gt;0/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/zH7HVUy.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;No indication of whether it is open today. The latest news seems to be the New Yearâs.&lt;/p&gt;

&lt;h3&gt;9. Dedham&lt;/h3&gt;

&lt;h2&gt;3/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/8qHlEVH.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;It is immediately clear that the library is closed today.&lt;/p&gt;

&lt;h3&gt;10. Dover&lt;/h3&gt;

&lt;h2&gt;2/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/ZmLY9lq.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;There is a clear indication that the library is closed today. I had to scan the page for a while and read a few things before I noticed it, so it was not obvious.&lt;/p&gt;

&lt;h3&gt;11. Framingham&lt;/h3&gt;

&lt;h2&gt;2.5/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/3j83pAP.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;It was almost obvious that âall libraries will be closedâ todayâââeven on this crowded page. I was distracted by the email sign-up notice, but the next thing I read was the closure notice. Not pretty, but close to functional.&lt;/p&gt;

&lt;h3&gt;12. Franklin&lt;/h3&gt;

&lt;h2&gt;0/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/9CnV6Uv.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;The public library website seems to be just a layer of content on top of the Franklin local government site. Very confusing. No indication of closure.&lt;/p&gt;

&lt;h3&gt;13. Holliston&lt;/h3&gt;

&lt;h2&gt;2.5/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/UNEAehM.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;I found the closure information quickly, but it did not stand out enough (for my taste) from other news.&lt;/p&gt;

&lt;h3&gt;14. Lexington&lt;/h3&gt;

&lt;h2&gt;3.5/3&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/n6IeQHX.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;The first indication of the library closure for MLK is in the featured image. It eventually changes to another feature, but there is a second indicator (Todayâs hours: CLOSED) that makes the situation obvious. This fall-back âclosedâ notice got this site an extraÂ .5 points on my scale.&lt;/p&gt;

&lt;h2&gt;What did I miss?&lt;/h2&gt;

&lt;p&gt;Of course, this is a very small test for a very specific user need. The sites that did well on my scale for âclosing hoursâ may fail miserably at providing an answer to âwhatâs the street address?â or âcan I renew my book online?â.&lt;/p&gt;

&lt;p&gt;This test reiterated for me the importance of research and real-life user testing. Knowing what problems people might try to solve by going to a website, and where the site fails them, is necessary for most any meaningful improvement.Â &lt;/p&gt;

&lt;h2&gt;How not to miss things:&lt;/h2&gt;

&lt;p&gt;As a designer, I am often excited by a problem I see, and can jump to a solution I consider to be self-evident. (&lt;em&gt;The page is too crowded. Letâs change the typeface and layout!&lt;/em&gt;) But to make my solutions truly useful to other people, I must know what they need.&lt;/p&gt;

&lt;p&gt;In this example, I am a user with a specific need. Designers do not often start working on a project with solid knowledge of user needs. To bridge this gap, we test the current product (if it exists), create personas and scenarios, and ask lots of questions.&lt;/p&gt;

&lt;p&gt;Research could have prevented the âis the library closed?â problem. If there was one question I could ask people,  it would be âWhat was the most frustrating thing about this library?â Out of many responses, I would imagine at least one would mention showing up at the library to find it closed. Asking these types of general questions, not &lt;em&gt;âhow satisfied are you with the library website? (on a scale from one to ten)â&lt;/em&gt;, will eventually lead us to meaningful design.&lt;/p&gt;

&lt;p&gt;Or, at least, save us the frustration of showing up to a closed library.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Joining DockYard</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/16/joining-dockyard" />
    <id>https://dockyard.com/blog/2015/01/16/joining-dockyard</id>
    <category term="jobs" label="Jobs"/><category term="culture" label="Culture"/><category term="team" label="Team"/>
    <published>2015-01-16 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Estelle DeBlois</name></author>
    <summary>Reflections on the past few months of being employed at DockYard</summary>
    <content type="html">&lt;p&gt;Six months ago today, I signed the letter officially accepting the offer
to join DockYard as a Senior Developer. It was the best decision I could have made.&lt;/p&gt;

&lt;p&gt;When I announced my resignation to my previous employer, he jokingly said that if
they had known choosing Ember as a new client-side framework would
eventually make me want to pursue a new Ember-focused opportunity, they would
have chosen Angular.&lt;/p&gt;

&lt;p&gt;I first started dipping my toes into Ember in late Spring 2013, some time after
Ember 1.0 RC3 was released. The Ember.js community was undeniably very active and
vibrant. That following June, I attended my first Boston Ember meetup,
where &lt;a href=&quot;https://twitter.com/dgeb&quot;&gt;Dan Gebhardt&lt;/a&gt; shared tips on testing Ember apps,
and &lt;a href=&quot;https://twitter.com/twokul&quot;&gt;Alex Navasardyan&lt;/a&gt; gave an introduction to Ember Data.
That&amp;#39;s how I came to know of DockYard.&lt;/p&gt;

&lt;p&gt;Soon, some names started to emerge as familiar names within the
community. &lt;a href=&quot;https://twitter.com/bcardarella&quot;&gt;Brian Cardarella&lt;/a&gt; became
known within our dev team as the one who wrote
&lt;a href=&quot;https://github.com/dockyard/ember-validations&quot;&gt;ember-validations&lt;/a&gt;,
which we were using in our application. &lt;a href=&quot;https://twitter.com/rwjblue&quot;&gt;Robert
Jackson&lt;/a&gt; was another name that kept popping
up on my Twitter and GitHub feeds. Call me a nerd if you will, but I was
as excited to have The Robert Jackson accept a fix that I submitted to
&lt;a href=&quot;https://github.com/emberjs/ember-dev&quot;&gt;ember-dev&lt;/a&gt; later that year to make builds
pass on Windows (with Rake at the time) as I would have been meeting a film celebrity.&lt;/p&gt;

&lt;p&gt;DockYard further reinforced its reputation by organizing the Wicked Good Ember
conference in Boston, in June of 2014, which I of course attended.&lt;/p&gt;

&lt;p&gt;Needless to say, when Brian reached out to me last July about joining the team, I
saw it as an opportunity that was really hard to pass on. Logistically,
I may have been better off staying where I was. I had a 40 min commute.
Joining DockYard would have doubled my commuting time. I was also
comfortable with the position I was holding, building out cool D3.js
charts with Ember, leading the development of new products, and getting
myself involved in all kinds of engineering team growth efforts. But
then there was DockYard. I went with my gut feeling instead and left
the warm and comfortable seat to face the exciting, though new and scary thing that was
DockYard.&lt;/p&gt;

&lt;p&gt;Scary? Yes. From everything DockYard had done for the Boston community
to the talent behind its wheel, I was absolutely terrified of not
fitting in, that it was too elite for me. I checked out the team page on
the website and read everyone&amp;#39;s biography a number of times,
trying to picture what kind of co-workers I would be interacting with
daily. No matter how great the projects can be, culture is a big thing.
To my delight, the culture at DockYard is one that resonates the
most with me in my 10 years of professional career.&lt;/p&gt;

&lt;p&gt;DockYard has a well-balanced team of young, bright minds and more
seasoned developers, and I embrace that. There is none of that &amp;quot;I am
better than you&amp;quot; bullshit. Those I once viewed as Ember Gods and would
have been intimidated to talk to have been incredibly supportive and encouraging.
In the past, whenever I was involved in the hiring process for
Engineering, I had always wondered where all the great developers were.
Well, they&amp;#39;re here, happily employed at places like DockYard. If there
is one thing I can say about the company, it&amp;#39;s that it&amp;#39;s doing something
right to attract an amazingly talented and diverse crew. I&amp;#39;ve been
particularly impressed with our designers. It&amp;#39;s nice as a developer to
work on such nifty UIs!&lt;/p&gt;

&lt;p&gt;Doing consultancy work was new to me, and I had been warned about what I was
throwing myself into, that I&amp;#39;d end up losing focus on quality and just
hack solutions together quickly to meet client deadlines. I don&amp;#39;t doubt
that those kinds of situations can creep up, but so far, I&amp;#39;ve found
quite the opposite in the two projects that I&amp;#39;ve been involved in.
People care deeply about delivering clean, maintainable,
and well-tested code, and they&amp;#39;ve been especially adept at maintaining those
principles throughout the life of a project.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s also refreshing to be able to work on a diverse portfolio of
projects. In the first few months since joining DockYard, I worked on a Rails and Ember app
that incorporated some really cool geolocation functionality. I am now
working on something that is unlike any other app I have ever developed.
The project includes Arduino code, Ember.js, and Node WebKit
(&lt;a href=&quot;http://nwjs.io/&quot;&gt;NW.js&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The best, of course, is DockYard&amp;#39;s mindset towards open source. I always
look forward to our &amp;quot;DockYard days&amp;quot; on Fridays to hack on code, blog
(this is my first one!), contribute back to the community in some ways,
or just to level up our craftsmanship.&lt;/p&gt;

&lt;p&gt;And as much as everyone works really hard, we also know when to have
fun, be it through Risk game tournaments, friendly games of Carcassonne
(or, as some would say, &amp;quot;Casserole&amp;quot;), or world exploring and building on
Minecraft.&lt;/p&gt;

&lt;p&gt;Finding a job that you&amp;#39;ll love can be hard. Finding a team that you&amp;#39;ll
love working with can be twice as hard. And sometimes, it&amp;#39;s okay
to leave behind what is comfortable and secure, in light of
something promising, yet unknown. You may be pleasantly surprised.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Job: Senior UI &amp; Visual Designer</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/14/sr-ui-designer" />
    <id>https://dockyard.com/blog/2015/01/14/sr-ui-designer</id>
    <category term="design" label="Design"/><category term="jobs" label="Jobs"/>
    <published>2015-01-14 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>Work at DockYard designing highly interactive web applications!</summary>
    <content type="html">&lt;p&gt;We are looking for the next addition to our design team.&lt;/p&gt;

&lt;p&gt;The ideal candidate is someone who can demonstrate a strong user-centric approach to their work, cares deeply about how their work will ultimately function, has been part of the user research process in the past, and shows strength in typography, color, and information layout.&lt;/p&gt;

&lt;p&gt;Weâre a design-driven software consultancy with design projects typically lasting 2-4 months. If youâre sick of working on the same product for years at a time, this may be a welcome change for you. Many of our client projects are âgreenfieldâ, so youâll have the opportunity to define the core concepts that will permeate throughout the application and be built upon as the product grows.&lt;/p&gt;

&lt;p&gt;We are also heavily involved in the Boston design community. We very successfully ran our first UX East Camp last Nov, we host and coorganize UX Boston, run UX Happy Hour, speak at industry conferences and meetups, and blog about our experience (blog traffic is around 300 hits per day). If youâre publishing your work and articles through DockYard they will get traction.&lt;/p&gt;

&lt;p&gt;You will be expected to take part in your community and we will give you tools to do so. We run weekly internal talks on a rotating schedule, run company wide peer-reviews of blog posts, and will fly you to one industry conference a year.&lt;/p&gt;

&lt;p&gt;DockYard also has a full engineering team on staff (actually much larger than the design team by about 2-to-1). They are experts in both front and back end technologies. The implementation of your work will be on-point and very well engineered.&lt;/p&gt;

&lt;p&gt;We offer better than market rates. Full health and dental coverage (no matter what your coverage requirements are). We also have 6 weeks of vacation time per year. 4 of those are mandatory vacation.&lt;/p&gt;

&lt;p&gt;This is an on-site position in Boston, MA.&lt;/p&gt;

&lt;p&gt;If this type of working environment interests you, then weâd love to hear from you. &lt;a href=&quot;mailto:jobs@dockyard.com&quot;&gt;E-mail us&lt;/a&gt; (we do not work with recruiters) to get in touch.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Check your expectations (at the bathroom door)</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/14/check-your-expectations" />
    <id>https://dockyard.com/blog/2015/01/14/check-your-expectations</id>
    <category term="design" label="Design"/><category term="observations" label="Observations"/>
    <published>2015-01-14 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Your normal is not always their normal.</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/8pbNwei.jpg&quot; alt=&quot;Person with gas mask&quot;&gt;
&lt;em&gt;This is what we walked through one Friday evening as we were leaving work.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The building we work in is under construction. There are many small and large annoyances that come with a live construction site nearby. One thing has been particularly awkward: access to our restrooms.&lt;/p&gt;

&lt;p&gt;As you might suspect, most if not all construction workers are men. There is active pipe work going on in the building, so they often need to do work directly inside the women&amp;#39;s restroom at random times throughout the day. We would discover that a man is working on a ceiling duct in a space we expected to be for women only, and it has caused a considerable amount of tension.&lt;/p&gt;

&lt;p&gt;While there may be many alternatives to doing construction work like this without warning, with less disruption of our work day, I had also started to question why this behavior felt like such an intrusion. After all, there are covered stalls with doors that go down close to the ground, so there&amp;#39;s still a significant amount of privacy.&lt;/p&gt;

&lt;p&gt;The reason seems to be not the exposure itself, but the fact that a certain space (e.g. beyond the door that says &amp;quot;WOMEN&amp;quot;) has been designated for a specific use, and is limited to one gender. This situation is not default - in fact, there are a few alternatives:&lt;/p&gt;

&lt;p&gt;Often located in smaller restaurants or coffee shops, a single-user bathroom normally does not have a gender restriction. One would simply wait for it to be vacant, and use it without a second thought.&lt;/p&gt;

&lt;p&gt;A &amp;quot;family&amp;quot; bathroom (explicitly marked as such) is for one or many users. It is roomier than the &amp;quot;regular&amp;quot; bathrooms next to it, and normally utilized by a parent with children, or someone using a wheelchair. Few eyebrows would be raised when several people at once, regardless of gender, walk out.&lt;/p&gt;

&lt;p&gt;At MOMA PS1 there is an explicitly declared unisex shared restroom. It has three stalls (with doors) and a urinal facing the back wall. It is a bit unsettling to use for the first time, but the explicit declaration makes it feel like a shared awkward experience, rather than a disadvantage of one group of people or another.&lt;/p&gt;

&lt;p&gt;In summary - our expectations always determine what we consider to be unacceptable. The example of bathrooms in our office building clearly shows that a construction worker&amp;#39;s expectation (&amp;quot;this is my work site&amp;quot;) and my female co-workers&amp;#39; expectation (&amp;quot;this is a space for women only&amp;quot;) did not line up. More importantly, both parties were &amp;quot;right&amp;quot; in their own way.&lt;/p&gt;

&lt;p&gt;To me as a designer, this awkward situation clearly illustrates how important it is to understand a client&amp;#39;s or a colleague&amp;#39;s expectations in any given situation. It is entirely possible â especially when working with a client in an industry I am not familiar with â to commit terrible missteps without even knowing they happened.&lt;/p&gt;

&lt;p&gt;To avoid the kind of toxic misunderstanding, it is important to communicate assumptions (even the &amp;quot;duh!&amp;quot; kind) early on in a project. It may feel awkward to have to say out loud the things that you consider to be understood by everyone involved. Get over it. When you find and defuse that one thing you did not agree was a given, it will all be worth it.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Masking private information from the owner</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/13/should-we-consider" />
    <id>https://dockyard.com/blog/2015/01/13/should-we-consider</id>
    <category term="design" label="Design"/><category term="observations" label="Observations"/><category term="privacy" label="Privacy"/>
    <published>2015-01-13 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>Are we allowing users to walk right into identity theft?</summary>
    <content type="html">&lt;h2&gt;Should we consider allowing the display of all private or risky information to the owner strictly through a prompt?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This could include:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;username&lt;/li&gt;
&lt;li&gt;password&lt;/li&gt;
&lt;li&gt;e-mail&lt;/li&gt;
&lt;li&gt;birth date&lt;/li&gt;
&lt;li&gt;social security number&lt;/li&gt;
&lt;li&gt;credit card info (maybe never show it)&lt;/li&gt;
&lt;li&gt;account numbers&lt;/li&gt;
&lt;li&gt;you get it by now&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Why?&lt;/h2&gt;

&lt;p&gt;Well, one little bit of information that someone tweets about themselves in a screenshot could mean theyâre sharing a useful piece of data to a DOXX operation by some douchebag on the internet. Thatâs the theory, but as I know very little about DOXXing it may not make sense.&lt;/p&gt;

&lt;h2&gt;Why am I thinking this?&lt;/h2&gt;

&lt;p&gt;I just tweeted a photo and I realized after the fact I might have put some sensitive information in it. Not like credit cards or actionable items to any normal viewer, but the kind of information that could add up to something a technically sophisticated malicious person might like. Turns out it was just my name, which seems ok to me.&lt;/p&gt;

&lt;h2&gt;Because users donât really know better and they never will&lt;/h2&gt;

&lt;p&gt;Iâve spent a lot of time resisting the âour users donât knowâ mantra in certain scenarios, and I can tell you why sometimes still resist it, but I digress. When it comes to security, our brains arenât very good at remembering the pieces of information weâve shared. I have 4k+ tweets and I know a lot of people are at that or beyond. How can we be sure we havenât shared too much information? I donât think we can.&lt;/p&gt;

&lt;p&gt;It could certainly be a pain in the designer&amp;#39;s ass to worry about protecting the user from doing something harmful to themselves (on purpose yet without being aware) in addition to everything else our daunting jobs require us to, but maybe this really warrants consideration by designers. Maybe itâs part of the job.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Book design and the web</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/13/book-design-and-the-web" />
    <id>https://dockyard.com/blog/2015/01/13/book-design-and-the-web</id>
    <category term="design" label="Design"/><category term="observations" label="Observations"/>
    <published>2015-01-13 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Really understand your content, then select its format.</summary>
    <content type="html">&lt;p&gt;I recently attended a presentation by a &lt;a href=&quot;http://www.ludovic-balland.ch&quot;&gt;Swiss book designer Ludovic Balland&lt;/a&gt; where he described the process behind his beautiful and sophisticated books. His studio has done many architecture monographs, because the format lends itself well to carefully considered custom design. (Architects with lots of work to show also tend to have the budget for and interest in such things.)&lt;/p&gt;

&lt;h2&gt;Formats in print&lt;/h2&gt;

&lt;p&gt;A key concept in his book design process is the selection of an appropriate medium, or format, for each type of content. He explained that with enough analysis, the materials from which a book is to be made can clearly be separated by type of content. For example, photographs of completed buildings are one type, and architectural drawings of incomplete or conceptual projectsâââanother. Once the separation is made, the next logical step is to select the best format for each type of content, with sensitivity to its beautiful representation. Type of paper, ink, printing methods, folding and binding possibilities all become variables in an equation, which can have a logical and aesthetic solution.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Barents Lessons&lt;/em&gt; is a book based on a trip that a group of students took to the Barents Sea.
(All images via &lt;a href=&quot;http://www.ludovic-balland.ch/&quot;&gt;ludovic-balland.ch&lt;/a&gt;)
&lt;img src=&quot;https://i.imgur.com/t0md8VR.jpg&quot; alt=&quot;Barents Lessons&quot;&gt;&lt;/p&gt;

&lt;p&gt;This book consists of three sections, with three distinct formats. The firstâââAnalysisâââis text, meant for long form reading.
&lt;img src=&quot;https://i.imgur.com/F1edPyY.jpg&quot; alt=&quot;Analysis&quot;&gt;&lt;/p&gt;

&lt;p&gt;It is followed by a section of detailed maps. Colors were individually selected to take advantage of the cartographic detail. For this and other projects, Ludovicâs studio often completely re-draws graphics like this all in a consistent style for the book, which they then can print at the highest quality.
&lt;img src=&quot;https://i.imgur.com/FDgyvQH.jpg&quot; alt=&quot;Maps&quot;&gt;&lt;/p&gt;

&lt;p&gt;The final section holds student photographs. They are shown in an order determined by the value of the photo: from dark to light, avoiding forced storylines between photographs that do not necessarily relate to each other. The paper selection has changed once again, and the photos are given full prominence with minimal captions.
&lt;img src=&quot;https://i.imgur.com/xZFCVHw.jpg&quot; alt=&quot;Photographs&quot;&gt;&lt;/p&gt;

&lt;p&gt;I find this book to be a great example of logical and thoughtful design: content is well supported and enhanced through the technology of book production. Everything, from the binding, to the paper, to the colors and page layouts, supports the content of the book. I also think itâs a strong parallel to the use of technology to support users, and the things they want to do, when we build products on the web.&lt;/p&gt;

&lt;h2&gt;Formats on the web&lt;/h2&gt;

&lt;p&gt;While technology allows us to make things respond in a specific manner to an action, to show only the necessary things to the right person, or to add delightful and playful details to already common tasks, it is the thoughtful and often economical selection of the âformatsâ we use on the web that makes for a strong, impactful project.&lt;/p&gt;

&lt;p&gt;For example, using Ember.js - &lt;a href=&quot;http://reefpoints.dockyard.com/2015/01/07/complex-search-pages-feel-better-in-ember.html&quot;&gt;a technology that allows us to change portions of a web page without reloading the entire thing&lt;/a&gt; - allows us to enhance a search page very effectively. We could use the same technology to enhance a gallery type page (whose primary purpose is to show static content) but the improvement would be marginal and not cost effective. The &lt;a href=&quot;http://www.indexhibit.org/what-who-why-how/&quot;&gt;Inexhibit platform&lt;/a&gt; focuses on &lt;em&gt;âa community of users who place emphasis on content over complicated website designâ&lt;/em&gt; and offers a minimal tool for artists to create a gallery and show their work.&lt;/p&gt;

&lt;p&gt;We can always add technology to marginally improve the experience. We could also print newspapers on higher quality paper, but the format would conflict with the nature of a newspaper as a frequently updated disposable item.&lt;/p&gt;

&lt;p&gt;Our ability to select the appropriate format, or technology, for a task reflects our deep understanding of the content and the problem we are solving. The rejection of unnecessary improvements is an important decision. It makes our work efficient and focused.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Why is Google ignoring over 400,000 backlinks to DockYard?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/11/why-is-google-ignoring-over-400000-backlinks" />
    <id>https://dockyard.com/blog/2015/01/11/why-is-google-ignoring-over-400000-backlinks</id>
    <category term="opinion" label="Opinion"/><category term="business" label="Business"/>
    <published>2015-01-11 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Imagine our enthusiasm when the opportunity to add hundreds of thousands
of backlinks from one of the web&amp;#39;s most popular library hosting websites
back to our domain came our way. And imagine our surprise when Google
decided they meant nothing.&lt;/p&gt;

&lt;p&gt;Back in &lt;a href=&quot;http://reefpoints.dockyard.com/2014/11/18/rubygems-redesign.html&quot;&gt;November we launched the redesign of
RubyGems.org&lt;/a&gt;. We were contacted by
&lt;a href=&quot;http://rubycentral.org&quot;&gt;RubyCentral&lt;/a&gt; about 9 months prior. I was
interested in this opportunity for three reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It gave DockYard the opportunity to give back to the Ruby community,
one that has been so pivotal to our growth early on (and one that has
been pivotal to my growth as a professional engineer for nearly 10
years)&lt;/li&gt;
&lt;li&gt;DockYard can show off its design talents to the community&lt;/li&gt;
&lt;li&gt;DockYard would get a &lt;em&gt;&amp;quot;Designed By&amp;quot;&lt;/em&gt; sponsor link at the bottom of
every page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This blog post is going to explore the third reason and the result of
this over the past two months.&lt;/p&gt;

&lt;p&gt;At the time of launch RubyGems.org had over 90,000 gems published. This
meant a sponsor link at the bottom of every page that was backlinking
to &lt;a href=&quot;https://dockyard.com&quot;&gt;DockYard.com&lt;/a&gt;. In addition to the landing page
and the other static pages. This was an appealing value to gain from a
re-design effort. According to Google&amp;#39;s own backlink search DockYard had
only 65 pages linking back. This struck me as odd considering this blog
itself links back to DockYard.com and there were more than 65 posts. But
surely after the redesign this number should go up. Our estimated
PageRank was &lt;code&gt;5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After the redesign we saw the expected spike in traffic&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/tpcgGpK.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Checking in on the referrals we can see that to date we have received
over 600 referrals from RubyGems.org. I&amp;#39;m OK with these numbers as I
never expected everyone to be clicking on those links.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/cM66gW5.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;However, what did shock me was that none of these backlinks were being
counted by Google.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/fTyXVzV.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;

&lt;p&gt;The sponsor link does not have a &lt;code&gt;nofollow&lt;/code&gt; attribute. And I admit that
SEO is not something I&amp;#39;ve very good at. But if I were to look at another
backlink source such as
&lt;a href=&quot;https://ahrefs.com/site-explorer/overview/subdomains/?target=dockyard.com&quot;&gt;ahrefs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/tlHt3sK.png&quot; alt=&quot;ahrefs&quot;&gt;&lt;/p&gt;

&lt;p&gt;You can clearly see the spike in referring pages. A &lt;strong&gt;huge&lt;/strong&gt; jump from
nearly nothing to over 400,000. The bottom graph shows that these are
primarly &lt;em&gt;DoFollow&lt;/em&gt; links.&lt;/p&gt;

&lt;p&gt;So these backlinks aren&amp;#39;t being counted by Google? Does Google only count
one domain per backlink? Color me confused. I suspect we&amp;#39;re doing
something wrong on our end to not get any credit. Could it be that such
a huge spike in backlinks are flagged as suspicious by Google? I&amp;#39;d
appreciate any thoughts in the comments.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Complex Search Pages Feel Better in Ember</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/07/complex-search-pages-feel-better-in-ember" />
    <id>https://dockyard.com/blog/2015/01/07/complex-search-pages-feel-better-in-ember</id>
    <category term="ember" label="Ember.js"/>
    <published>2015-01-07 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Creating a better search experience with Ember</summary>
    <content type="html">&lt;p&gt;With many server rendered search pages, a change to your search parameters
typically renders a new page. The use of some JavaScript can alter the
search results, as seen below. Note that both refreshes and JavaScript results
swapping happens.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/pstevGCOUHs&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Whenever the results are altered, it feels (and is) slow. The times that
refresh the whole page feel the slowest, but even when a partial
change happens, it&amp;#39;s obvious and slow. It feels clunky&lt;/p&gt;

&lt;p&gt;With Ember, we can provide a better experience. The video below is a similiar
style search page on a site we built for &lt;a href=&quot;http://learnivore.com&quot;&gt;Learnivore&lt;/a&gt; with Ember.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/7F2F1iGOw4s&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Notice that the page never refreshes completely. The search box always stays on
the page. And when we switch categories, only the relevant options are swapped
out, we don&amp;#39;t have to redraw the whole page. And when we select an additional
filter on the left, only the search results are swapped out. &lt;strong&gt;This page performs
better because it performs less work.&lt;/strong&gt; It feels better because you are constantly
seeing parts of the page reloaded without being changed. The filters on the left
only change when they need to.&lt;/p&gt;

&lt;p&gt;It will also perform better on low bandwith connections; it only requests the
data necessary to render the page.  This will require fewer bytes to be sent
compared to the server rendered page.  When you render the page on the server,
you have to include every tag necessary to render that content. When you are
using a single page application architecture like Ember, it will only need the
data that makes up that result.&lt;/p&gt;

&lt;p&gt;What a representation of the server rendered page looks like coming across the
web to your device:&lt;/p&gt;
&lt;div class=&quot;highlight html &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Your search results&lt;span class=&quot;tag&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;&amp;lt;!-- Several to tens of lines for stylesheets and javascript --&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Search results!&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This can be tens of lines, hundreds of characters to establish content
      and look&lt;span class=&quot;tag&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;somepage&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Here is one of the search results&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Some description of your search result&lt;span class=&quot;tag&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;SomeImage&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;&amp;lt;!--Repeat the result 10/20/50 times --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;about&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;gt;&lt;/span&gt;About us&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hundreds more characters to provide links, style, etc&lt;span class=&quot;tag&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Since the page needs to be completely reloaded, we need to display not only
the contents, but any header and footer content. This simplified example also
lacks any type of filters or inputs to alter your results, which would make the
amount of data sent to your device larger to view the page. This needs to happen
whenever the page is updated.&lt;/p&gt;

&lt;p&gt;Compare the above to what Ember requires to update the page:&lt;/p&gt;
&lt;div class=&quot;highlight json &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;: [
    {
      &lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;, &lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;,
      &lt;span class=&quot;error&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;, &lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;
    },
    &lt;span class=&quot;error&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;integer&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;integer&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;
  ]
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Bytes are wasted sending down the markup to render the page; it&amp;#39;s already
there, along with the header and footer. This payload is much smaller, and
provides a friendlier experience to those on a slow connection.&lt;/p&gt;

&lt;p&gt;We can provide better interactions with Ember because the user will not see unnecessary
rerendering of the same content. The requests to update the content will be
smaller, so new results will arrive faster. The difference in speed of these two
approaches is increased as the user&amp;#39;s bandwidth shrinks. Faster pages help with
conversions, and Ember can provide a faster, more intuitive experience.&lt;/p&gt;
</content>
  </entry><entry>
    <title>BEM Tips: Avoid Chaining Modifiers</title>
    <link rel="alternate" href="https://dockyard.com/blog/2015/01/05/avoid-chaining-modifiers" />
    <id>https://dockyard.com/blog/2015/01/05/avoid-chaining-modifiers</id>
    <category term="css" label="Css"/>
    <published>2015-01-05 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Amanda Cheung</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;At DockYard, we use the BEM methodology for naming our CSS classes. BEM
stands for Block, Element, Modifier and is a front-end development
technique that suggests a class naming convention for your HTML elements. If
you aren&amp;rsquo;t already familiar with BEM, it would be helpful to take a look at
&lt;a href=&quot;http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/&quot;&gt;Harry Robert&amp;rsquo;s MindBEMding blog post&lt;/a&gt;
and the &lt;a href=&quot;https://bem.info/&quot;&gt;BEM website&lt;/a&gt; first.&lt;/p&gt;

&lt;p&gt;When I started looking into using BEM, I thought it would definitely work well
for large web applications. The more rules we could put in place
regarding naming conventions, the better. What I didn&amp;rsquo;t understand
was what to do when an element could be considered an element of a block &lt;em&gt;or&lt;/em&gt; a
modifier. If I had a button that was in the footer and it was styled differently
than other buttons in the website, should it be named &lt;code&gt;.footer__button&lt;/code&gt;
or &lt;code&gt;.button--footer&lt;/code&gt;? Arguments could be made for both sides, so is one better
than the other?&lt;/p&gt;

&lt;p&gt;After trying out both ways, &lt;code&gt;.footer__button&lt;/code&gt; proved more scalable because
this rule could be consistently applied in more situations. Could there
be more types of buttons in the footer?
If there are also social buttons in the footer, our choices now become
&lt;code&gt;.footer__button--social&lt;/code&gt; or &lt;code&gt;.button--footer--social&lt;/code&gt;. In the second one, is social modifying
footer and footer modifying button? Or is social modifying button as
well? To avoid confusion, I would call it &lt;code&gt;.footer__button--social&lt;/code&gt;
and not chain my modifiers. This doesn&amp;rsquo;t mean we
shouldn&amp;rsquo;t use multiple modifiers in a class name at all.
&lt;code&gt;.person--female__hand--right&lt;/code&gt; is still fair game. It&amp;rsquo;s clear that female
is modifying person and right is modifying hand.&lt;/p&gt;

&lt;h2&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;If I had an element that could potentially be either an element of a
block or modifying an element, the latter is better because
chaining modifiers can be confusing.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Tips on Mental Models</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/12/30/modeling-mental-models" />
    <id>https://dockyard.com/blog/2014/12/30/modeling-mental-models</id>
    <category term="design-thinking" label="Design Thinking"/><category term="design" label="Design"/><category term="design-process" label="Design Process"/>
    <published>2014-12-30 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>A few things to keep in mind.</summary>
    <content type="html">&lt;p&gt;Just as a single color can have conflicting associations between different cultures, mental models can vary widely between users. If you havenât heard of &lt;a href=&quot;http://en.wikipedia.org/wiki/Mental_model&quot;&gt;mental models&lt;/a&gt;, they are a beholderâs mental image of a designed object and how it may be interfaced with.&lt;/p&gt;

&lt;p&gt;Understanding the mental models your users have created of your product (or similar product experiences) is important. It will help you improve either by adjusting the product to better fit their mental model or by changing the usersâ mental model to better fit your product. Neither are simple.&lt;/p&gt;

&lt;p&gt;To give you a sense of how a mental model is constructed or applied to a product, let&amp;#39;s imagine looking at a new object in extreme slow motion:&lt;/p&gt;

&lt;p&gt;The object is placed before you. The first thing you notice is its size and shape. Itâs small enough to fit in the palm of your hand, thin, and rectangular in shape. Its color is off-white. In this first glance you might make some general assumptions about the objectâs nature and function, but given that there are countless objects that could share these qualities, your observation continues.&lt;/p&gt;

&lt;p&gt;On the grey rectangle you can clearly see a small red button, a small green button, a large square button, and a series of small grey buttons in a familiar 3x3 grid. Given that the device is small enough to fit in your hand, has multiple buttons, and lacks a screen, you might conclude that itâs a remote of some kind. And you might stop there, unless you actually have to use the remote.&lt;/p&gt;

&lt;p&gt;While making these observations, your brain was building a mental model of how to interact with it by referencing past experiences with similar objects. Taking the path of least resistance, your brain wants to reapply these models wherever and whenever it can. You wonât need to re-teach yourself how to use something youâve consistently used over the years unless something significantly breaks the pattern. With each connection you make with familiar and unfamiliar qualities of the object, either consciously or not, you pave ways to interpret the purpose, value, and effectiveness of the object.&lt;/p&gt;

&lt;p&gt;The speed with which we identify these things correlates to how similar the object is in form to other objects weâre familiar with. The models you create as a user arenât originating solely with the object in front you; instead they are created from all the objects youâve ever interacted with. This is where understanding and employing mental models gains value in design. We can use them to manipulate, speed up, or slow down interpretation of our products.&lt;/p&gt;

&lt;p&gt;The information and interpretations from that first glance are all gleaned with relatively low effort, almost instantaneous, and youâre not always aware that you are making these evaluations. However, a unique object often takes a conscious effort to understand. If the object wasnât very well designed to reveal its own function you may instead have exhausted yourself with a seemingly uninterpretable thing and given up.&lt;/p&gt;

&lt;h2&gt;Borrowing&lt;/h2&gt;

&lt;p&gt;We sometimes borrow mental models from unrelated or contextually irrelevant experiences because some aspect of what we are interacting with may have unconsciously reminded us of previous experiences. A thing isnât always what we think it is.&lt;/p&gt;

&lt;p&gt;Because we are all somewhat responsible for building our own mental models from our experiences with the designed world, our interpretations of an objectâs purpose or quality of performance can vary greatly. I think this is part of the reason why reviews of products are so polarized. Peopleâs expectations and preferences are different, and sometimes they just arenât able to build a fitting mental model of the product. So theyâll borrow it.&lt;/p&gt;

&lt;p&gt;If the object is truly unique, layers of mystery may remain for a broad user base. Thus, there may be limits to how they have evaluated the objectâs purpose. As designers, we donât need to hold ourselves responsible for explaining everything, but it is important to get a user to as complete an understanding as possible using the objectâs form alone. No language, no manuals, no tutorials. No automatically playing videos after they log in for the first time.&lt;/p&gt;

&lt;h2&gt;Against the grain&lt;/h2&gt;

&lt;p&gt;Going against the grain of a mental model is generally a bad idea, but it can be valuable. It should be by design, of course, and might provide some comparative market value and interest. An example of this working was the introduction of the iPod and its very unique interface (the wheel) while competitors had basically indistinguishable and boring (by comparison) arrow key pads. The iPod might have been a little more difficult to use, but the innovative design wasnât enough of a challenge to stop people from using it. Instead the change helped Apple greatly differentiate their product from other MP3 players.&lt;/p&gt;

&lt;p&gt;What happens when you go against the grain for no good reason? Lots of avoidable and silly mistakes, thatâs what. Take this remote for our projector as an example.
&lt;img src=&quot;https://i.imgur.com/ybHKog9.jpg&quot; alt=&quot;A very frustrating projector remote&quot;&gt;
&lt;em&gt;For emphasis, Iâve erased the small labels generally ignored by users when turning the projector on or off.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We know itâs a remote at first glance because weâve used them before. The shape seems to suggest both purpose and a direction for use. Which end of the remote would you point toward the projector?&lt;/p&gt;

&lt;p&gt;If you said youâd point it with the slanted side forward and the red button in the upper right, you would have found on your first (and second, and third) attempt that this remoteâs form does not align with your mental model. With this particular design, you are expected to hold the remote with the red button positioned on the bottom left. &lt;/p&gt;

&lt;p&gt;In other words, the mental model I have for remotes is not matched to the device because the manufacturer ignored a common design pattern without apparent reason, adding only momentary confusion, rather than enhanced functionality, to my experience.&lt;/p&gt;

&lt;h1&gt;Last words on defining (and refining) your models&lt;/h1&gt;

&lt;p&gt;When designing your product, be aware of your usersâ mental models and recognize that your own will be very different from theirs. This is an overwhelmingly common mistake.&lt;/p&gt;

&lt;p&gt;You should also be aware of user and market contexts to judge what aspects of their models you may break and which you should keep. Donât break the model just to be different if the difference provides no value or delightful experience for a user.&lt;/p&gt;

&lt;p&gt;Lastly, designers must understand that users will have wildly varying points of reference, so presumed models need to be tested with multiple different users before the direction of the product design is settled upon. Failure to do this will put the success of the product at risk.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Lessons Learned - Three years of running a software consultancy</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/12/28/lessons-learned-three-years-running-a-software-consultancy" />
    <id>https://dockyard.com/blog/2014/12/28/lessons-learned-three-years-running-a-software-consultancy</id>
    <category term="opinion" label="Opinion"/><category term="business" label="Business"/>
    <published>2014-12-28 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;This year&amp;#39;s story is one of how we nearly went out of business &lt;em&gt;twice&lt;/em&gt; yet
still managed to pull off our most successful year yet.&lt;/p&gt;

&lt;h2&gt;People&lt;/h2&gt;

&lt;p&gt;In 2013, we ended the year with 11 employees. We made a key hire at the start of the year with &lt;a href=&quot;http://twitter.com/rwjblue&quot;&gt;Robert
Jackson&lt;/a&gt; joining us. I had met Robert a few
months prior at &lt;a href=&quot;http://burlingtonrubyconference.com/&quot;&gt;Burlington Ruby
Conf&lt;/a&gt;. Robert had been
contributing to a few of our Ember libraries, as well as making a name
for himself by quickly moving up the contributors list in Ember.js
itself. Less than four months after we hired Robert he was welcomed onto
the Ember.js Core Team. I&amp;#39;m extremely proud of him accomplishing
that.&lt;/p&gt;

&lt;p&gt;We added depth to our design team in Q1 2014 with &lt;a href=&quot;http://twitter.com/rgbcolor&quot;&gt;Maria Matveeva&lt;/a&gt;
and &lt;a href=&quot;http://twitter.com/imakemusic&quot;&gt;Tim Walsh&lt;/a&gt;. Tim and Maria have been
invaluable for us, their dedication and ability allows you to easily
forget how young they are. I&amp;#39;m looking forward to seeing how they
continue to grow in 2015.&lt;/p&gt;

&lt;p&gt;Early in 2014, we hired our first Project Manager, &lt;a href=&quot;https://twitter.com/jon_lacks&quot;&gt;Jon
Lacks&lt;/a&gt;. Jon and I went to college
together, and historically I have not had a good run of
working with friends. That has been my fault, I think I was more
interested in working with people I was friends with than establishing
what their responsibilities would be. Jon and I agreed that any and all
potential issues that may arise that could conflict with our prior
relationship should be aired out immediately. Jon joined
DockYard in February and spent the first month or so observing our team
more than taking complete ownership of our process. I gradually handed
off some of what I was managing to Jon (running standups, getting involved with
some client meetings, helping with estimations). All this to say that
adding a dedicated PM was one of the highest impact decisions I made in
2014. I suspect that many companies don&amp;#39;t need one until they&amp;#39;re around
10 people in size but once you do hire one you&amp;#39;ll be thankful.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/i_am_romina&quot;&gt;Romina Vargas&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/Linstula&quot;&gt;Lin Reid&lt;/a&gt; were two engineers that went through our
intern program and we upgraded them to full-time as soon as we could.
Both Lin &amp;amp; Romina have been important members of some of our larger
clients projects in 2014.&lt;/p&gt;

&lt;p&gt;Marin Abernethy, a former engineering intern, came back for her third (and final)
internship with us after her graduation from college.
In the Fall we hired her as a full-time engineer.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/netopwibby&quot;&gt;Paul Webb&lt;/a&gt; interviewed with us in early 2014 but we had some projects
fall through and things got very tight for us (more on this later) so we
had to pass. But as soon as we had the bandwidth we brought Paul onboard
to our UX Development team.&lt;/p&gt;

&lt;p&gt;Heading into the Summer, we started to get spread a little thin on the
engineering team. I had come off of client work completely to focus on
the business so we needed another Senior level engineer. I reached out
to &lt;a href=&quot;https://twitter.com/edeblois&quot;&gt;Estelle DeBlois&lt;/a&gt;, who had come to our
&lt;a href=&quot;http://wickedgoodember.com&quot;&gt;Wicked Good Ember&lt;/a&gt; conference in June.
She&amp;#39;s been lead developer for one of our larger clients over the past
few months.&lt;/p&gt;

&lt;p&gt;Our final hire starts full-time with us in January. &lt;a href=&quot;https://twitter.com/ashleytreni&quot;&gt;Ashley
Treni&lt;/a&gt; was actually tending bar at
&lt;a href=&quot;http://www.highballboston.com/&quot;&gt;Highball Lounge&lt;/a&gt; right next door to our
office (they can see us, we can see them). She asked what we did and it
turns out that she is an amazing designer who was completing her Masters
in Information Design and Visualization at Northeastern. She did a summer internship with us and
accepted our offer for full-time employment just recently.&lt;/p&gt;

&lt;h3&gt;Hiring is hard&lt;/h3&gt;

&lt;p&gt;Hiring continues to be hard. We have had success by focusing on
technology niches, but we may have tapped that out. Going into 2015, we
will have to consider how do we reach out and attract top talent,
&lt;em&gt;and&lt;/em&gt; how do we improve the existing talent we have. Promoting from within
is something I&amp;#39;ve talked a big game about but have done little with.
This will change in 2015.&lt;/p&gt;

&lt;p&gt;I began 2014 with the same trend I had in the previous two years: I
would hire good people even if we didn&amp;#39;t have projects to put them on.
Coming out of Q1 2014, I had to stop this immediately. While we had built
up a great team, the weight of that payroll and our lack of cashflow at
the time was at a breaking point where I could no longer cover the
difference by taking myself off salary. Since then I have been very
conservative with hiring. Unfortunately we actually missed out on some
great people because of this, and I regret that as I was perhaps &lt;em&gt;too&lt;/em&gt;
conservative in our hiring at the time. Heading into 2015, this will
probably continue to be an aspect of the company I will continue to
improve.&lt;/p&gt;

&lt;h3&gt;Firing still sucks&lt;/h3&gt;

&lt;p&gt;I had to fire two employees in 2014. Firing always sucks and I don&amp;#39;t
think I&amp;#39;ll ever get used to it. There is a guilt that is attached that
at some point is out-weighed by whatever you&amp;#39;re not getting from said
employee. So how does one mitigate the guilt? &lt;a href=&quot;http://www.slideshare.net/reed2001/culture-1798664?ref=https://gigaom.com/2013/01/29/netflix-company-culture/&quot;&gt;Netflix has a great
policy when it comes to firing
employees&lt;/a&gt;.
The document outlines their full cultural philosophy but the gist of how
they fire is that they give a very generous severance package. So
managers don&amp;#39;t concern themselves with the guilt what will happen to
this employee without their job. I think this is a great idea, but not
always practical for all companies. If we had Netflix money then I would
definitely align our severance package with theirs.&lt;/p&gt;

&lt;h3&gt;Culture&lt;/h3&gt;

&lt;p&gt;We&amp;#39;ve done a lot of work to define what the culture of DockYard actually
is. Until Q4 2014 our culture was never written in stone. So we took
some time to put it into words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;strong problem solvers, with attention to detail&lt;/li&gt;
&lt;li&gt;coachable learners and willing mentors&lt;/li&gt;
&lt;li&gt;professional, kind and respectful&lt;/li&gt;
&lt;li&gt;collaborative team players&lt;/li&gt;
&lt;li&gt;disciplined&lt;/li&gt;
&lt;li&gt;reputation&lt;/li&gt;
&lt;li&gt;diverse&lt;/li&gt;
&lt;li&gt;fun&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&amp;#39;m sure you&amp;#39;re looking at this list and thinking &amp;quot;yeah this is pretty much what every company will say&amp;quot;.
That could be true, but these are going to be our hiring and retention criteria. We will be building a team around 
these principles and expect everyone at DockYard to live up to them.&lt;/p&gt;

&lt;h3&gt;Heading into next year&lt;/h3&gt;

&lt;p&gt;We have a goal of expanding our team to over 25 by the end of 2015. I
would actually prefer to be closer to 30. Our hiring will be focused on
Senior Level talent for engineering, design, and UX. We&amp;#39;re always interested
in &lt;a href=&quot;mailto:jobs@dockyard.com&quot;&gt;hearing from great people, get in touch if you&amp;#39;re
interested&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Estimations&lt;/h2&gt;

&lt;p&gt;Our problems with maintaining our estimations were not significantly
improving in early 2014. We had to eat a lot of money on contracts that
was due either to bad estimations or our inability to properly manage our
clients. If we ever expected to build a real company, this had to be
fixed. This is where Jon came in as our first Project Managing hire. It
took a few months but we&amp;#39;ve gone from being consistently late to being
consistently early. Our estimations are currently one of the more
reliable aspects of our business. This has not just helped relationships
with existing clients but being able to reliably sell our services to
new clients is incredibly powerful.&lt;/p&gt;

&lt;h3&gt;Heading into the next year&lt;/h3&gt;

&lt;p&gt;I suspect we will continue to hone our ability to estimate. We will also
be looking to hire an additional Project Manager as we decided we don&amp;#39;t
ever want to spread a PM over more than three projects.&lt;/p&gt;

&lt;h2&gt;Financials&lt;/h2&gt;

&lt;p&gt;In 2013 we ended the year with $1.7m in revenue with about 20% profit
margin. This year we improved that to $3.1 in revenue with 33% profit
margin. This is a significant jump, in many ways I&amp;#39;m incredibly proud of
what we were able to accomplish this year. However, I also know that we
(as a company) underperformed. If we had been as productive in the first
half of the year as we were in the second half we should have been
closer to a $4m+ company with &amp;gt;50% profit margin.&lt;/p&gt;

&lt;h3&gt;What went wrong&lt;/h3&gt;

&lt;p&gt;We were getting contracts coming in through the year, but nothing with
the challenge or scope that I was hoping for. Small $50k contracts here
and there. I like working on small projects but from a business
perspective we were burning too much time negotiating contracts,
balancing people on and off between contracts. I was butting heads with
our business developer. He and I had different ideas on how to run the
company. The funny thing is that neither of us were wrong. He wanted to
reduce price due to lack of the demand we had at the time. I didn&amp;#39;t want
to do that. I was willing to pass on contracts that we could have
gotten if we cut our rate 25%. This eventually put us in a position of
bringing in 0% of billings for more than 50% of the company rather than
75% of billings. Which would you rather have?&lt;/p&gt;

&lt;p&gt;I&amp;#39;m sure there are people reading this was a deeper background in
running a business than saying it was stupid not to take the 75%. Here
is my problem: at that amount we weren&amp;#39;t making any profit and our
people were tied up on projects. I was tired of living hand to mouth, I
had taken myself off of payroll consistently for the past few years. I
was living off my wife&amp;#39;s salary.&lt;/p&gt;

&lt;p&gt;At the end of Q1 I was looking down the barrel of DockYard and not
liking what I was seeing. Then we got a whale of a contract come our
way. This was a contract that could right the ship. Or so I thought.&lt;/p&gt;

&lt;p&gt;I was not heading up the contract negotiations. The only criteria I gave
was what I thought our rate should be for this contract. When it came to
it our business developer was not confident that we could get that rate.
I was distraught. I was not willing to lock DockYard into a long-term
contract at cost. I told my wife at dinner I was going to start looking
for a &amp;quot;real job&amp;quot; and that DockYard was finished.&lt;/p&gt;

&lt;p&gt;I didn&amp;#39;t sleep. I stayed up and kept mulling over the contract, was this
it? I came to several conclusions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client could afford our rate.&lt;/li&gt;
&lt;li&gt;We were worth the rate.&lt;/li&gt;
&lt;li&gt;Our business developer did not believe in #2&lt;/li&gt;
&lt;li&gt;I should be handling contract negotiations for DockYard&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I came into work that morning. Within a span of 15 minutes I fired our
business developer and landed the client at the rate we felt we
deserved.&lt;/p&gt;

&lt;p&gt;I realize the above might seem indifferent to letting someone go. He and
I actually got along very well on a personal level. But as I mentioned
previously when it came to how to run DockYard we didn&amp;#39;t see eye to eye.
I was stressing out over this constantly and in the event I was not able
to land this client on my own at the very least I could say that I went
out my way. Egotistical? Yes, of course. But it is something I needed to
do. If we had slowly died over the rest of 2014 due to no real profit
margin I would have quit.&lt;/p&gt;

&lt;p&gt;This was the first of two near-deaths for DockYard this year. The second
would come just two months later.&lt;/p&gt;

&lt;p&gt;The large client came with a large legal team, one that I was unprepared
for handling properly. We have an excellent lawyer we&amp;#39;re working with
but I am accustomed to contract negotiation taking maybe a week. This
took months to complete.&lt;/p&gt;

&lt;p&gt;The problem with dealing with Enterprise companies is that they can
outlast you. It isn&amp;#39;t their intent to do so, it is in their best
interest that their vendors are able to work on what they need to the
best of the vendor&amp;#39;s ability. It doesn&amp;#39;t help either party if the vendor
can&amp;#39;t make payroll. However, because of how many Enterprise companies
are structured, and who has to sign off on what, an unprepared small
vendor can be put into a position of agreeing to some things that are not
in its best interest so it can start getting paid ASAP.&lt;/p&gt;

&lt;p&gt;I was perhaps too  risky in this regard. I held out on the contract, I
put it through multiple rounds of negotionation. There was some legit
scary stuff in it that I was not willing to agree to. We had started
work with the client before the contract was completed. At the time I
didn&amp;#39;t consider this to be a big risk.&lt;/p&gt;

&lt;p&gt;What happened was that there was little to no incentive to speed up the
contract signing for our client. We were working, doing what they
wanted, and they had no obligation to pay us. I realize some of you are
reading this and thinking &amp;quot;Rookie Move!&amp;quot; but consider the context.
Starting work with large clients prior to contracts being completed is
actually a common practice in the Enterprise. I hear some of you
screaming &amp;quot;no it isn&amp;#39;t!&amp;quot;. Yes, it is.&lt;/p&gt;

&lt;p&gt;We ran out of money. We had a payroll that we were $25k short for. I had
a very difficult conversation with the client and made the tough
decision to stop work until the contract was signed and our existing
invoices were immediately covered. I made a personal loan to DockYard to
cover payroll. (as a side-note, banks never loan you money when you need
it) Thankfully the client saw the situation for what it was and we were
able to move forward. This was in June.&lt;/p&gt;

&lt;p&gt;Putting the brakes on the project and getting the contract done and
getting paid was the turning point for DockYard. We went from invoicing
on average $30k/week to over $100k/week. With no contract longer than
Net-30 by August we had all of our debts paid off and were in a position
to hire again. By November we had gone from a 1% profit margin for the
year in June to over 25%.&lt;/p&gt;

&lt;p&gt;It is actually strange writing about this now, and I&amp;#39;m not entirely
certain I should have written all of this. In some ways it was one of
the most stressful times in my life, and looking back it feels surreal.&lt;/p&gt;

&lt;p&gt;I hope there are some nuggets of knowledge in here to help others avoid
a similar situation.&lt;/p&gt;

&lt;h3&gt;Heading into next year&lt;/h3&gt;

&lt;p&gt;We have ambitious financial goals. We aim for a $5m+ business in 2015. A
$10m+ business in 2016, each year with &amp;gt;25% margin. If we can maintain our current momentum we
should easily meet 2015&amp;#39;s goal.&lt;/p&gt;

&lt;h2&gt;Technology&lt;/h2&gt;

&lt;h3&gt;Ember.js&lt;/h3&gt;

&lt;p&gt;We bet very heavily on &lt;a href=&quot;http://emberjs.com&quot;&gt;Ember.js&lt;/a&gt; in 2013. That bet
has paid off very well for us in 2014. The client mentioned above hired
us for our expertise in Ember.js. We landed another great client in the
Summer because of Ember.js. We are seeing a steady flow of work come in
because of Ember.js but I don&amp;#39;t think we can meet our $5m goal by
relying on inbound leads from Ember.js.&lt;/p&gt;

&lt;p&gt;One thing we&amp;#39;ve never dealt with is selling our services into another
company. We&amp;#39;ve got most work by companies making a technology decision then
finding who is good at working with said technology. How do you convince
a company unfamiliar with Ember.js that it is what they should use to
build their product with? What if this person is not technology savvy?&lt;/p&gt;

&lt;p&gt;I came to the conclusion that you cannot sell Ember.js directly. I
needed help with building a sales pipeline and sales pitch. A friend put
me in touch with &lt;a href=&quot;https://www.linkedin.com/pub/lorne-cooper/0/9a6/811&quot;&gt;Lorne
Cooper&lt;/a&gt; who I have
been working with over the past two months. Lorne convinced me that I
had sales backwards. We need to start with Marketing. (he also convinced
me that I couldn&amp;#39;t sell Ember.js)&lt;/p&gt;

&lt;p&gt;So what we built was the DockYard marketing funnel. Working backwards
from Ember.js, we broadened the funnel. If the answer is: &lt;strong&gt;Ember.js&lt;/strong&gt;
then the question should be &lt;strong&gt;What is the best Single Page App
framework?&lt;/strong&gt; (let&amp;#39;s save tech debates for another time). I didn&amp;#39;t feel
that selling SPAs was any better than selling Ember.js. Again, the
answer is &lt;strong&gt;Single Page Apps&lt;/strong&gt; so the question should be &lt;strong&gt;How do you
provide a modern user experience on the web?&lt;/strong&gt;. Now were had something.
Selling UX as a solution to companies was tangible. If we could market
that UX improvements was the way to solve common problems in modern web
apps then we could hook companies on the idea that Single Page Apps was
the best way to deliver modern UX. If we could convince companies on
SPAs then we have the chance to convince them that Ember.js is the best
framework for building out SPAs. At this point we have to make a case
that DockYard is the best company as building Ember.js applications. We
now had our marketing funnel. We plan on putting this funnel to the test
in early 2015, but don&amp;#39;t expect any significant number of qualified
leads to be produced until late 2015, more likely early 2016.&lt;/p&gt;

&lt;h3&gt;Elixir&lt;/h3&gt;

&lt;p&gt;While we are not currently writing any &lt;a href=&quot;http://elixir-lang.org&quot;&gt;Elixir&lt;/a&gt; apps I think 
it will be part of our offerings around Q3 2015. Specifically because of
the &lt;a href=&quot;http://www.phoenixframework.org/&quot;&gt;Phoenix Framework&lt;/a&gt; being very
similar to &lt;a href=&quot;http://rubyonrails.org&quot;&gt;Ruby on Rails&lt;/a&gt; I think we should be
able to ramp upon it quickly.&lt;/p&gt;

&lt;p&gt;The other choices I considered looking into were
&lt;a href=&quot;http://golang.org&quot;&gt;Go&lt;/a&gt; and &lt;a href=&quot;http://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt;. Elixir
feels like the best of the three to me. It is far less popular than the
other two but considering it is backed by Erlang and boasts the most
approachable syntax, has meta-programming, concurrency, and is built for
fault tolerance I feel of those three language Elixir is the best suited
for the future. Of course, this is a gamble and time will tell.&lt;/p&gt;

&lt;h3&gt;Ruby on Rails&lt;/h3&gt;

&lt;p&gt;Our involvement with Ruby on Rails will never go away completely but I
don&amp;#39;t see Ruby or Rails being a serious part of our technology identity
in the future. I would like to think that we were out with a bang
though, in early 2014 we were selected to redesign
&lt;a href=&quot;http://rubygems.org&quot;&gt;RubyGems&lt;/a&gt;. We launched the redesign at
&lt;a href=&quot;http://rubyconf.org&quot;&gt;RubyConf&lt;/a&gt; and it was a nice way to say &amp;quot;thank-you&amp;quot;
to a community that we&amp;#39;ve benefited from for so long.&lt;/p&gt;

&lt;h3&gt;Heading into next year&lt;/h3&gt;

&lt;p&gt;I always want DockYard to be a company that does not stagnate on
technology. I enjoy working with and exploring new technology and I
always want to push our engineering team to do that same. In the near
future I think Ember.js and Elixir will be important for us, of course
we must be open-minded enough about new technology on the horizon.&lt;/p&gt;

&lt;h2&gt;Design&lt;/h2&gt;

&lt;p&gt;Design has become so essential to our process I don&amp;#39;t understand how we
go by in the early years without a dedicated design team. We rely upon
design to manage our Discovery Phase, build and inform our estimations.
Design has more impact on us converting a client out of Discovery to a
full client than engineering does.&lt;/p&gt;

&lt;h3&gt;UX East&lt;/h3&gt;

&lt;p&gt;This year we ran our first Design conference, &lt;a href=&quot;http://uxeast.org/&quot;&gt;UX East&lt;/a&gt;.
It was structured as a design camp with two talks and one workshop.  The conference was organized by our Creative Director Steven Trevathan
and Maria Matveeva we believe we were hugely successful.&lt;/p&gt;

&lt;p&gt;We&amp;#39;re already beginning plans for next year&amp;#39;s UX East (you can sign up for
updates, including call for proposals, &lt;a href=&quot;http://eepurl.com/_NCUL&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;Team Structure&lt;/h3&gt;

&lt;p&gt;Every project is now assigned at least two designers. This is partially
because the projects are big enough to merit the team, but it&amp;#39;s also a huge
qualitative add to the final delivery. Pairing designers is really helpful for &amp;quot;leveling up&amp;quot; as well. Matching
designers by their different strengths they&amp;#39;ll help each other grow. The
concept is very similar to pair programming, however the designers go
through many rounds of critiques instead of using the same computer for an
extended period.&lt;/p&gt;

&lt;p&gt;While we hadn&amp;#39;t previously done this, and it looks like a fairly obvious
improvement to make, the result has been surprisingly positive and our most
recent projects are seeing a huge benefit from it.&lt;/p&gt;

&lt;h3&gt;Setting Goals &amp;amp; Sticking To Them&lt;/h3&gt;

&lt;p&gt;One thing we&amp;#39;re very good at is coming up with ideas. Lot&amp;#39;s of them. There is
no shortage there, however there is a real challenge in effectively using down
time and DockYard Fridays to commit to delivering on those ideas. I believe
this is due to not having specific departmental goals that directly fit into
company annual or quarterly objectives.&lt;/p&gt;

&lt;p&gt;An example of this challenge is &lt;a href=&quot;http://toolsofthetrade.dockyard.com/&quot;&gt;Tools of the Trade&lt;/a&gt;.
In the beginning of 2014 we put effort into creating small and novel icon packs
and distrubuting them as free to use. It generated some interest, and we had
fun with our icons, but we dropped the ball and lost momentum on it. Not because
we didn&amp;#39;t enjoy making them or that it didn&amp;#39;t benefit our designers by the
challenge, but because it didn&amp;#39;t fit cleanly into any company objective.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ve set a Q1 2015 goal to create a program and agenda for design experimentation
with a focus on single page web applications. By that objective we&amp;#39;ll be aiming
to provide more practical design tools, design and interaction patterns, and free
assets for other designers in creating single page web applications. By commiting
to this goal and using Tools of the Trade as vehicle, we should be able to promote
ourselves, &amp;quot;level up&amp;quot; our designers, and effectively utilizing downtime.&lt;/p&gt;

&lt;h2&gt;Business&lt;/h2&gt;

&lt;p&gt;On the business side of things we&amp;#39;ve begun to add more structure to DockYard. We hired a CEO coach 
to take us through an OGSM (Objectives, Goals, Strategies and Measures)
planning session for 2015. It was a tiring two days of time that helped
us discover what type of company we want to be. The management team has
all decided that DockYard should aim big and that is what we&amp;#39;re going to
do.&lt;/p&gt;

&lt;h3&gt;Office Space&lt;/h3&gt;

&lt;p&gt;In Q2 2015 we&amp;#39;ll be moving into a new office space. Our current space
has served us well but it has its problems. The new space will be
modern and have plenty of space for us (we&amp;#39;re upgrading from 2,800 sq/ft to
7,800 sq/ft). I&amp;#39;m excited to share those plans in the upcoming months.&lt;/p&gt;

&lt;h2&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;I hope this year&amp;#39;s reflection has been useful for you in some way. Each
year&amp;#39;s summary has felt different and I&amp;#39;m sure next year&amp;#39;s will too. As
a company DockYard has taken some knocks this year but we came out
stronger for it with more focus and an actual gameplan. I&amp;#39;d love to hear
other&amp;#39;s experiences as well in the comments.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Pattern Matching in Elixir for Rubyists</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/12/26/pattern-matching-in-elixir-for-rubyists" />
    <id>https://dockyard.com/blog/2014/12/26/pattern-matching-in-elixir-for-rubyists</id>
    <category term="ruby" label="Ruby"/><category term="elixir" label="Elixir"/>
    <published>2014-12-26 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;This is the first in a series of posts for helping Ruby devs understand
some of the concepts in Elixir.&lt;/p&gt;

&lt;h2&gt;Pattern Matching&lt;/h2&gt;

&lt;p&gt;Pattern Matching is one of my favorite Elixir features. Let&amp;#39;s take a
look. (using an &lt;a href=&quot;http://elixir-lang.org/getting_started/7.html#7.2-maps&quot;&gt;Elixir
Map&lt;/a&gt;)&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;%{foo: bar} = %{foo: &amp;quot;baz&amp;quot;}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above is matching a pattern. Don&amp;#39;t think of &lt;code&gt;=&lt;/code&gt; as assignment, you
should think of &lt;code&gt;=&lt;/code&gt; as &lt;em&gt;equality&lt;/em&gt;. The left-hand side of the &lt;code&gt;=&lt;/code&gt; is
equal to the right-hand side. Through pattern matching the variable
&lt;code&gt;bar&lt;/code&gt; is assigned the value &lt;code&gt;&amp;quot;baz&amp;quot;&lt;/code&gt;. Consider:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;[foo, bar] = [1, 2]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;foo&lt;/code&gt; is assigned &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; is assigned &lt;code&gt;2&lt;/code&gt;. Patterns can match to
any depth:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;[foo, bar, [baz]] = [1, 2, [3]]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;here &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; have the same value from the previous example but
&lt;code&gt;baz&lt;/code&gt; is now assigned the value of &lt;code&gt;3&lt;/code&gt;. Alternatively if we had written:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;[foo, bar, baz] = [1, 2, [3]]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;baz&lt;/code&gt; is now assigned the value of &lt;code&gt;[3]&lt;/code&gt;. This would be an example of a
semi-greedy matcher. You can expand upon this to greedily match the
entire statement:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;my_list = [1, 2, [3]]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;code&gt;my_list&lt;/code&gt; greedily matched to the entire right-hand side of the
&lt;code&gt;=&lt;/code&gt;. So why is this cool? Let&amp;#39;s take a look at a Ruby method that
has some conditions:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;foo&lt;/span&gt;(a, b, c)
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; a == &lt;span class=&quot;symbol&quot;&gt;:something&lt;/span&gt;
    ...
  &lt;span class=&quot;keyword&quot;&gt;elsif&lt;/span&gt; b == &lt;span class=&quot;symbol&quot;&gt;:other&lt;/span&gt;
    ...
  &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;
    ...
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above is likely something familar to many Ruby devs. This presents
some problems. Any methods with several code paths increases the
complexity of the method. Complex methods can be difficult to test in
isolation. Let&amp;#39;s take a look at how this would be implemented in Elixir:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def foo(:something, b, c) do
  ...
end

def foo(a, :other, c) do
  ...
end

def foo(a, b, c) do
  ...
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first question Ruby devs have is &lt;em&gt;why are there three functions of the same
name?&lt;/em&gt; In Elixir you can define multiple functions of the same name as
long as the function signatures are unique. Functions are matched
against the values passed in. So &lt;code&gt;foo(:something, 2, 3)&lt;/code&gt; would match the
first &lt;code&gt;foo&lt;/code&gt; defined. &lt;code&gt;foo(1, :other, 3)&lt;/code&gt; matches the second. &lt;code&gt;foo(1, 2,
3)&lt;/code&gt; matches the third. Match priority is the order in which the
functions are defined.&lt;/p&gt;

&lt;p&gt;Now our functions are concise, and focused on the very specific
behavior. The conditional is obfuscated through the pattern matching but
this is a common design pattern in Elixir so it should be embraced.&lt;/p&gt;

&lt;p&gt;The pattern matching can be more complex:&lt;/p&gt;
&lt;div class=&quot;highlight elixir &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;def foo(%{foo: bar}, &amp;quot;baz&amp;quot;) do
  ...
end
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above will match: &lt;code&gt;foo(%{foo: &amp;quot;zeb&amp;quot;}, &amp;quot;baz&amp;quot;)&lt;/code&gt; but would not match
&lt;code&gt;foo(%{foo: &amp;quot;zeb&amp;quot;}, &amp;quot;bar&amp;quot;)&lt;/code&gt; because the second argument does not match.&lt;/p&gt;

&lt;p&gt;Take a look at the &lt;a href=&quot;http://elixir-lang.org/getting_started/4.html&quot;&gt;Elixir Pattern Matching
Guide&lt;/a&gt; for more
information.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Importance of Process, and Why It Matters</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/12/12/importance-of-process" />
    <id>https://dockyard.com/blog/2014/12/12/importance-of-process</id>
    <category term="process" label="Process"/><category term="opinion" label="Opinion"/>
    <published>2014-12-12 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Paul Webb</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I joined DockYard in April of this year, after leaving a small startup. Before that, I was at another
startup and doing lots of freelance/agency work. In all of these places, there was never an existing
process in place, aside from what was in my head. For better or worse, this was fine and allowed me to
get work done. What I have learned since joining DockYard however, is that my old method of working is
dangerous for a bigger company and just does not work.&lt;/p&gt;

&lt;p&gt;Initially, I resisted changing my process, like a fool/jerk. Why should I? My process has worked for
years, it was inherently superior! &lt;em&gt;Obviously&lt;/em&gt;, this was not true. I got too comfortable with how I
had been coding and ignored requests to learn about &lt;a href=&quot;http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax&quot;&gt;BEM syntax&lt;/a&gt; and organizing my CSS in a different order. Applying most
of these new techniques to my own personal projects allowed me to see the usefulness to our UX team&amp;#39;s
(evolving) process. It was then that I realized, process is not about you or I, it is about the team.&lt;/p&gt;

&lt;p&gt;If I am working on a project for six months and spin off to another project, another UX developer can
pick up where I left off and understand the code I have written. If everyone wrote code the way they
felt like, there would be so much time lost (and wasted) trying to figure out what the original coder
meant when they wrote something. Money would be lost as well because time would not be spent on doing
actual work.&lt;/p&gt;

&lt;p&gt;Process improves productivity and productivity allows the team to gain a better understanding of what
is possible for the company as a whole. Which, in the long run, creates better opportunities and
projects for all of us.&lt;/p&gt;

&lt;h4&gt;TL;DR&lt;/h4&gt;

&lt;p&gt;Be open to new ideas about process. If it does not make sense to you, apply it to your own work before
completely dismissing it.&lt;/p&gt;
</content>
  </entry><entry>
    <title>HTMLBars: Calling All Testers</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/11/30/htmlbars_calling_all_testers" />
    <id>https://dockyard.com/blog/2014/11/30/htmlbars_calling_all_testers</id>
    <category term="ember" label="Ember.js"/><category term="ember-cli" label="Ember-cli"/><category term="htmlbars" label="Htmlbars"/>
    <published>2014-11-30 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Robert Jackson</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;HTMLBars support has landed in Ember&amp;#39;s canary channel thanks to the tireless work
of the HTMLBars team. Make sure to chat them up at &lt;a href=&quot;http://emberconf.com/&quot;&gt;EmberConf&lt;/a&gt; (you
are going right?!?!) for some war stories.&lt;/p&gt;

&lt;p&gt;We are nearing the end of the 1.9 &lt;a href=&quot;http://emberjs.com/builds/#/beta&quot;&gt;beta cycle&lt;/a&gt; (aiming for 2014-12-06)
which means we will be making the go / no-go decision on all pending features in Canary when we branch
for the next beta cycle. Clearly, we would all love to have 1.10 use HTMLBars.&lt;/p&gt;

&lt;p&gt;In order to enable the HTMLBars feature flag in the 1.10 betas (shipping around 2014-12-09), we need
help confirming that no major issues exist. This is where &lt;em&gt;you&lt;/em&gt; come in!&lt;/p&gt;

&lt;h3&gt;Using Canary Builds with Ember CLI&lt;/h3&gt;

&lt;p&gt;Upgrading to the canary channel with Ember CLI is very straightforward.&lt;/p&gt;

&lt;h4&gt;Update Bower&lt;/h4&gt;

&lt;p&gt;Run the following:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;rm -rf bower_components
bower install --save handlebars#~2.0.0
bower install --save ember#canary
bower install
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Bower also prompts you to confirm various &amp;quot;resolutions&amp;quot; that it is unsure of. Make sure you
pick &lt;code&gt;ember#canary&lt;/code&gt; and Handlebars 2.0 if prompted.&lt;/p&gt;

&lt;h4&gt;Update NPM Dependencies&lt;/h4&gt;

&lt;p&gt;Run the following:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;npm uninstall --save-dev broccoli-ember-hbs-template-compiler
npm install --save-dev ember-cli-htmlbars
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h4&gt;Summary&lt;/h4&gt;

&lt;p&gt;Now we have successfully updated to the latest canary builds of Ember. Next up: HTMLBars.&lt;/p&gt;

&lt;h3&gt;Using HTMLBars with Ember CLI&lt;/h3&gt;

&lt;p&gt;Enabling HTMLBars is as simple as adding the following to your &lt;code&gt;config/environment.js&lt;/code&gt; (under
&lt;code&gt;EmberENV.FEATURES&lt;/code&gt; section):&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;EmberENV: {
  FEATURES: {
    &#39;ember-htmlbars&#39;: true
  }
},
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now restart any running &lt;code&gt;ember serve&lt;/code&gt; commands you have and you should be running with HTMLBars.&lt;/p&gt;

&lt;h3&gt;Report Issues&lt;/h3&gt;

&lt;p&gt;This part is critical: Please report any issues &lt;a href=&quot;https://github.com/emberjs/ember.js/issues&quot;&gt;at GitHub&lt;/a&gt;,
especially regressions from 1.8 or 1.9-beta. If your business has certain browser requirements (IE8 for example)
testing on those edge-case platforms today will help us resolve issues in time for 1.10.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Wish List</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/11/28/ember-wish-list" />
    <id>https://dockyard.com/blog/2014/11/28/ember-wish-list</id>
    <category term="ember" label="Ember.js"/><category term="opinion" label="Opinion"/>
    <published>2014-11-28 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;It&amp;#39;s getting close to Christmas and I&amp;#39;ve got a few things on my list for
Tomster Claus this year. All of my wishes are about making my
applications smaller. One of the constant complaints I see about Ember
is that it is &amp;quot;too fat&amp;quot;. You may not know this but this problem is
solveable and can actually grow alongside Ember to ensure your assets
are a slim as they can be. On to the wish list!&lt;/p&gt;

&lt;h3&gt;Tree Shaking&lt;/h3&gt;

&lt;p&gt;Are you familiar with Tree Shaking? The concept is simple, a dependency
graph of your application is built. Let&amp;#39;s say one of your files requires
&lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;C&lt;/code&gt;. And &lt;code&gt;A&lt;/code&gt; requires &lt;code&gt;D&lt;/code&gt;, and &lt;code&gt;F&lt;/code&gt;. And &lt;code&gt;C&lt;/code&gt; required &lt;code&gt;F&lt;/code&gt;.
Currently with Ember CLI all files for all of your dependencies will get
included in the final build. So if there is an &lt;code&gt;E&lt;/code&gt; file it will be in
the final build even if you are not using it in any way, this is wasteful.
With ES6 the dependency graph can be built between your files, any files
that are not in the graph are not included in the final built. They are
&amp;quot;shaken&amp;quot; out of the build process. This means a smaller footprint for your assets.&lt;/p&gt;

&lt;p&gt;There are two major hurdles to implementing this in Ember CLI right now.
The first is that doing a static analysis on the dependency graph may
result in false positives of what files to ignore for the build. While
there are many files that you are depending upon via the &lt;code&gt;import&lt;/code&gt;
statement:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { foo, bar } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;baz&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is very easy to parse. But your application can also import
resources via the Ember Resolver:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;container.lookup(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;model:foo&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A few levels down a &lt;code&gt;resolveOther&lt;/code&gt; function is called and &lt;code&gt;lookup&lt;/code&gt; is
turned into a &lt;code&gt;require&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;my-app/models/foo&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;parsing this out is not as simple. We could just assume everything in
the app&amp;#39;s namespace should be part of the final build, but when other
libraries are doing more complex tricks with importing this presents a
problem. For example, in the latest version of Ember Validations the
validators themselves live in the &lt;code&gt;ember-validations&lt;/code&gt; namespace. You can
override validators by placing them in your namespace. The lookup is
something like this:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;lookupValidator&lt;/span&gt;(name) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; container.lookup(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;validator:&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;+name) ||
    container.lookup(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-validations@validator:&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;+name);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;How do we properly parse this out to include the correct validators in
the dependency graph? One solution might be for library authors to
declare which files should always be included in the final build, but
this defeats the purpose of only including what is being used. If the
application is using the Presence Validator but not the Inclusion
Validator why would I want those extra LOCs?&lt;/p&gt;

&lt;p&gt;The other major hurdle is Ember itself. While Ember&amp;#39;s source is in ES6
form the final build that you get is in AMD. Which means it is one file.
Ember will have to be distributed in the original ES6 form. I am also
not a fan of the current package names. If this ever happens I would
much prefer:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Component from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember/component&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;rather than&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Component from &lt;span class=&quot;error&quot;&gt;`&lt;/span&gt;ember-views/views/component&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Separate builds&lt;/h3&gt;

&lt;p&gt;Ember CLI is all or nothing right now. Which means that you have a
single build pipeline for your application assets (&lt;code&gt;app-name.js&lt;/code&gt;) and a single build
pipeline for 3rd party assets (&lt;code&gt;vendor.js&lt;/code&gt;). It would be nice to define
additional assets that can be built into final files. For example, &lt;a href=&quot;https://github.com/dockyard/ember-admin/issues/32&quot;&gt;this
request for Ember
Admin&lt;/a&gt;. Technically
this could be done right now but it would require some heavy hacking of
the vendor asset pipeline in Ember CLI. Personally I would like to see
an API for this specifically. Perhaps it could be in the form of isolating a namespace to
be ignored in the &lt;code&gt;vendor.js&lt;/code&gt; final concat but still output in the
&lt;code&gt;dist/&lt;/code&gt; directory.&lt;/p&gt;

&lt;h3&gt;Async code loading&lt;/h3&gt;

&lt;p&gt;This wish dove-tails off the previous one. Now that we have our separate
assets how do we safely load them into our Ember apps? If we are
isolating the assets I would think this implies they aren&amp;#39;t meant for
consumption at application launch. Going back to the Ember Admin
example, not all users need those LOCs. Only when an authorized user
hits the admin functionality should it pull down the Ember Admin assets
and plug into the app. This would be ideal. The major hurdle here is
with how the container currently works. Perhaps something like this
could put it on the right track:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;function&quot;&gt;resolveOther&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(name) {
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (needAsyncLoad(name)) {
    asyncLoad(name).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
      &lt;span class=&quot;comment&quot;&gt;// after this load completes the name&lt;/span&gt;
      &lt;span class=&quot;comment&quot;&gt;// would be removed from the list of&lt;/span&gt;
      &lt;span class=&quot;comment&quot;&gt;// resources requiring async loading&lt;/span&gt;
      resolveOther(name);
    }
  } &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt; {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; require(name);
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This would allow even further shrinking of the initial applicaiton
footprint. Only include what is necessary, async load other assets. This
creates the illusion of speed which is just as good as actual speed. You
will have the trade-off of periodic sections of your app with a longer
than normal loading state, but that should only happen once per
application instance.&lt;/p&gt;

&lt;h3&gt;Wishes to reality&lt;/h3&gt;

&lt;p&gt;Fulfilling these wishes should go a long way to negating the &amp;quot;too fat&amp;quot; argument for
Ember. Here&amp;#39;s to hoping that 2015 will see a more lean Tomster.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Rubygems.org Redesign</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/11/18/rubygems-redesign" />
    <id>https://dockyard.com/blog/2014/11/18/rubygems-redesign</id>
    <category term="design" label="Design"/><category term="ruby" label="Ruby"/>
    <published>2014-11-18 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Wy7zNYB.png&quot; alt=&quot;RubyGems Redesign&quot;&gt;&lt;/p&gt;

&lt;p&gt;Today I am very proud to announce that the DockYard-led redesign of
&lt;a href=&quot;http://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; has been launched.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://rubycentral.org&quot;&gt;Ruby Central&lt;/a&gt; just announced and put into production a redesign of Ruby&amp;#39;s
most popular community website during the Lightning Talk session at
&lt;a href=&quot;http://rubyconf.org&quot;&gt;RubyConf 2014&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The redesign effort was led by &lt;a href=&quot;https://twitter.com/LoganFaerber&quot;&gt;Logan
Faerber&lt;/a&gt; and built out by &lt;a href=&quot;https://twitter.com/acacheung&quot;&gt;Amanda
Cheung&lt;/a&gt;. You can see how happy it has
made them.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/l6jQ1f0.jpg&quot; alt=&quot;Hooray!&quot;&gt;&lt;/p&gt;

&lt;p&gt;We would have been lost without the guidance from Ruby Central folks &lt;a href=&quot;https://twitter.com/evanphx&quot;&gt;Evan
Phoenix&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/dwradcliffe&quot;&gt;David Radcliffe&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/indirect&quot;&gt;AndrÃ© Arko&lt;/a&gt;. As well as some insight from &lt;a href=&quot;http://twitter.com/qrush&quot;&gt;Nick Quaranto&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We were very fortunate to have been selected. We hope that everyone
enjoys the new look!&lt;/p&gt;
</content>
  </entry><entry>
    <title>UX East Camp 2014</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/11/18/we-did-it" />
    <id>https://dockyard.com/blog/2014/11/18/we-did-it</id>
    <category term="ux-east" label="Ux East"/><category term="design" label="Design"/><category term="design-process" label="Design Process"/><category term="design-thinking" label="Design Thinking"/><category term="conferences" label="Conferences"/><category term="uxeast" label="Uxeast"/>
    <published>2014-11-18 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Steven Trevathan</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://uxeast.org/&quot; title=&quot;UX East Camp&quot;&gt;We did it.&lt;/a&gt; This weekend went far better than we ever could have imagined. Weâre grateful and maybe a tad bit emotional, so bear with us.&lt;/p&gt;

&lt;p&gt;The camp was initially intended as somewhat of a proof of concept, but became something much more real than that. Beyond proving that we are all willing to spend 3 days living with complete strangers, we experienced the unique value of the connections, friendships, and mentoring that this style of event facilitated. It turns out that the people who pay good money for and spend a whole weekend on such a unique social and learning environment are exactly the type of people who make it worthwhile. The need to learn, share, and be challenged by their peers is in their blood. This is who they are, and theyâre the people we want to bring together.&lt;/p&gt;

&lt;p&gt;It goes without saying: &lt;a href=&quot;https://twitter.com/michelleyaiser&quot; title=&quot;Michelle Yaiser&quot;&gt;Michelle&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/StayingInDroves&quot; title=&quot;Ed King&quot;&gt;Ed&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/CalamityJD&quot; title=&quot;JD Jordan&quot;&gt;JD&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/benjordan&quot; title=&quot;Ben Jordan&quot;&gt;Ben&lt;/a&gt; did much more than they were asked to and were the core of what made the camp so great. They shared their wisdom, challenged us to solve hilariously weird and unique problems, guided us, and befriended us. They poured their hearts into this and we are proud and humbled to have had them for our first UX East Camp.&lt;/p&gt;

&lt;p&gt;The event was a risk, but the speakers and attendees overwhelming proved to us that it can and should be done. So weâre going to do it again.&lt;/p&gt;

&lt;p&gt;See you next year at UX East Camp, Spring 2015.&lt;/p&gt;
</content>
  </entry><entry>
    <title>My project for UX Camp</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/11/12/bring-to-ux-east" />
    <id>https://dockyard.com/blog/2014/11/12/bring-to-ux-east</id>
    <category term="user-experience" label="User Experience"/><category term="design" label="Design"/><category term="conferences" label="Conferences"/><category term="design-process" label="Design Process"/><category term="ux-east" label="Ux East"/><category term="ux-camp" label="Ux Camp"/><category term="uxeast" label="Uxeast"/>
    <published>2014-11-12 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Maria Matveeva</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;This weekend, I am heading to &lt;a href=&quot;http://uxeast.org/&quot;&gt;UX East&amp;#39;s camp&lt;/a&gt; in Maine. It is kind of like a conference, except you also get the opportunity to work on your own project and get feedback from others while there. I am helping organize the event, and a large chunk of my time will be spent taking photos and helping with other random tasks, so I wanted to bring a project thatâs small and easy to manage.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/K9TBWR9.jpg&quot; alt=&quot;sketches&quot;&gt;&lt;/p&gt;

&lt;p&gt;My project is practicing how to quickly sketch ideas by hand.&lt;/p&gt;

&lt;p&gt;When I first started as a UX Designer at &lt;a href=&quot;https://dockyard.com/&quot;&gt;DockYard&lt;/a&gt;, I noticed how confident the other designers were at sketching. &lt;a href=&quot;https://dockyard.com/team#logan-faerber&quot;&gt;Logan&lt;/a&gt; just happens to be a &lt;a href=&quot;https://dribbble.com/shots/1765074-UX-East-Icons?list=users&amp;amp;offset=3&quot;&gt;kickass illustrator&lt;/a&gt;, which helps. But still, I felt like I lacked confidence in comparison. Iâve been trying to improve, but had not tried anything focused on sketching specifically yet.&lt;/p&gt;

&lt;h2&gt;Why is sketching useful?&lt;/h2&gt;

&lt;p&gt;Sketching is a great tool not only to produce work deliverable to the client (hand drawn wireframes are often part of the Discovery phase in our work) but also a way to think more clearly. If I can articulate an idea through a drawing, I have a good understanding of it. In the process of drawing something out, I also find the fuzzy areas that need more definition, and I am able to ask better questions as a result.&lt;/p&gt;

&lt;p&gt;Writing on a subject is similar to this exploratory sketching. By trying to write on a subject, I find unexplained pieces, and am forced to form my thoughts clearly. But writing only uses one aspect of an idea. Visuals are something else. I want to rely on both verbal (writing) and visual (drawing) thinking in my work.&lt;/p&gt;

&lt;h2&gt;How to practice?&lt;/h2&gt;

&lt;p&gt;I decided to focus on practicing only the skill to express a single idea through a very simple drawing. As an art supply enthusiast, it is easy for me to get carried away in selecting just the right pen, paper or color for a project. To counter this, I limited my tools: a clipboard, a single medium-weight black marker, and a sizable stack of half-sheets of printer paper.&lt;/p&gt;

&lt;p&gt;I further limited possible distractions by deciding not to focus on high quality, thoughtful drawings, and instead produce many simple drawings. For this reason, I will also not look for great reference material, but try to just get the visual idea down on paper quickly instead.&lt;/p&gt;

&lt;p&gt;I will also focus on actually drawing, rather than annotating. In the few practice drawings I made so far I resorted to writing the details I could not get into the drawing. It would be great to get away from this.&lt;/p&gt;

&lt;p&gt;When I finish one of these simple drawings, I will slide it to the bottom of the stack so Iâm ready to start another one. I will not focus on judging the results too quickly.&lt;/p&gt;

&lt;p&gt;At camp, I might share the drawings I make, and ask for feedback on how to make them more clear. Will they make sense? With some practice, I hope that they do.&lt;/p&gt;

&lt;p&gt;So, hereâs what I am working on. Pretty simple, and should be fun! I also asked a couple of colleagues what they are planning to doâââand here it is:&lt;/p&gt;

&lt;h2&gt;What Steve is working on&lt;/h2&gt;

&lt;p&gt;He&amp;#39;s going to work on a video game idea that originally started as a web-comic at DockYard. In addition to that he&amp;#39;s taking a look at some various prototyping tools (as well exploring InVision a little deeper).&lt;/p&gt;

&lt;h2&gt;What  Tim is working on&lt;/h2&gt;

&lt;p&gt;Tim has been working on a typeface that is targeted to be both practical and highly legible. He&amp;#39;s hoping to gain some feedback from fellow campers and continue chipping away at the lowercase letterforms.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Pitch This</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/11/07/pitch-this" />
    <id>https://dockyard.com/blog/2014/11/07/pitch-this</id>
    <category term="opinion" label="Opinion"/><category term="business" label="Business"/><category term="marketing" label="Marketing"/>
    <published>2014-11-07 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Here is something I probably shouldn&amp;#39;t be admitting: I can&amp;#39;t put
together a sales pitch for my own company.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s not that I don&amp;#39;t know what we do, I am intimately familiar with
what we do. It&amp;#39;s not that I don&amp;#39;t believe in us, in fact we
have big growth plans for the next 3 years and I am certain we&amp;#39;ll meet
them. It&amp;#39;s just that I find it incredibly difficult to describe to
others in an &amp;quot;elevator pitch&amp;quot; what a software consultancy can offer
without going down the &amp;quot;technology&amp;quot; rabbit hole.&lt;/p&gt;

&lt;p&gt;The exercise is: &lt;em&gt;if I were introduced to someone at a party, how do I convince them they should 
hire DockYard&lt;/em&gt;? Funny enough, I can&amp;#39;t do it. This is a very large
deficiency for me/my company right now. To date &lt;strong&gt;all&lt;/strong&gt; of our
contracts have been from inbound sales. Which is great, but we need to
be able to sell our services to companies that don&amp;#39;t yet know about us.&lt;/p&gt;

&lt;p&gt;So what does DockYard do? According to our current landing page &lt;em&gt;We
create web &amp;amp; mobile applications&lt;/em&gt;. Which is 100% true, but if I told
this to you I doubt you&amp;#39;d hire us. I asked other DockYard&amp;#39;ers to try
their hand at writing the DY pitch. To illustrate how difficult this is
here is what they came up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;DockYard designs and develops applications for people who have an idea and don&amp;#39;t know what to do next&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We build web products, and focus on quality.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We create software that helps people. A client can come to us seeking advice regarding software development practices or looking to implement a product he/she has been thinking about. Our main focus is delivering a solution that a client is happy with by using powerful visual design, best software engineering practices and latest technologies.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We&amp;#39;re a design and development shop specializing in really intuitive, responsive user interfaces. We work primarily with Ember.js, which is a JavaScript framework similar to Angular and Backbone. On the backend, we prefer a Rails backend and transactional database, which is more reliable than the NoSQL databases out there.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;DockYard leads projects from ideas to user-friendly products that are built by cutting edge technologies and methodologies. As a team, we put clients&amp;#39; business goals in the forefront through the collaborative expertise of our designers and developers.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;DockYard helps business owners create web apps with the combined power of Ember and great design.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We&amp;#39;re a team of software designers and engineers deeply invested in producing the best solution to a challenge, rather than just the one that works.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We do a lot of research before we start designing, so our projects are thought through. Designers have a lot of say in what we actually build, compared to other shops, so it makes the work more meaningful.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of these go beyond the scope of a &amp;quot;pitch&amp;quot; but I think the message is clear: this is not an easy assignment. 
The common theme is the focus on our expertise, which is a good angle. Expertise has been what defines DockYard.
But do all companies care about &lt;strong&gt;how&lt;/strong&gt; we build? &lt;/p&gt;

&lt;p&gt;Currently nearly all of our clients get in touch with us because
of our expertise in Ember.js. At that point the sale is
actually quite easy. There aren&amp;#39;t a lot of consultancies right now
claiming expertise in Ember. Amongst those firms I believe that
DockYard is considered one of the top. So by the time the client
contacts us they have probably already decided to go with us. This is
great but it paints us into a niche. We&amp;#39;re missing out on the other
99.99% of the opportunities that don&amp;#39;t know about us.&lt;/p&gt;

&lt;p&gt;So how do some other software consultancies pitch? I don&amp;#39;t know if it is
fair to use the marketing tagline from their website as their &amp;quot;pitch&amp;quot;
but I think it is close enough for the purposes of this article. Let&amp;#39;s
take a look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Thoughtworks&lt;/strong&gt; &lt;em&gt;We provide software delivery, pioneering tools and
consulting for organizations with ambitious missions.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pivotal Labs&lt;/strong&gt; &lt;em&gt;We transform how the world builds software.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;thoughtbot&lt;/strong&gt; &lt;em&gt;Our clients hire us to design and build their
products. We focus on user outcomes and simplicity. We write code for
iOS, Android, and the web.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;37signals&lt;/strong&gt; &lt;em&gt;an elite team of expert web design and usability
specialists dedicated to simple, clear, and useable customer-focused
design.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don&amp;#39;t know if this really helps me or confuses me even more. These are
all over the place, from general, to technology specific, to downright
vague. Each of these companies have been very successful. How much of
their success do they owe to their sales pitches? &lt;strong&gt;37signals&lt;/strong&gt; (when
they were a consultancy) was famous for being a referral based business.
(or at least advertising themselves as such) I don&amp;#39;t know &lt;strong&gt;thoughtbot&lt;/strong&gt;
as well as I used to but I believe they still don&amp;#39;t have any internal
sales team. &lt;strong&gt;Thoughtworks&lt;/strong&gt; and &lt;strong&gt;Pivotal&lt;/strong&gt; both have sales/biz-dev
teams. Their marketing lines are very vague, very &amp;quot;wide-net&amp;quot;. No help
here.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s sad to say but I am currently at a loss on how to effectively sell my own company. &lt;/p&gt;
</content>
  </entry><entry>
    <title>Motivation vs Discipline</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/10/30/motivation-vs-discipline" />
    <id>https://dockyard.com/blog/2014/10/30/motivation-vs-discipline</id>
    <category term="opinion" label="Opinion"/>
    <published>2014-10-30 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;We&amp;#39;ve all seen the &lt;strong&gt;Motivational Posters&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/ChxXPmT.jpg&quot; alt=&quot;Motivate&quot;&gt;&lt;/p&gt;

&lt;p&gt;I always hear people talk about
&lt;strong&gt;motivation&lt;/strong&gt;. &lt;em&gt;What motivates you?&lt;/em&gt; &lt;em&gt;I&amp;#39;m lacking motivation.&lt;/em&gt; Well I&amp;#39;m
here to tell you that motivation is bullshit.&lt;/p&gt;

&lt;p&gt;Motivation may get you to take on a task or behavior that you don&amp;#39;t
normally do but eventually that motivation will either not be there any
more or won&amp;#39;t be effective. Then you&amp;#39;ll slip, and you justify it by
thinking &lt;em&gt;&amp;quot;well I just lacked proper motivation&amp;quot;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Motivation&lt;/em&gt; as a concept is a cop-out. If you feel that you need
motivation to accomplish your goals you will likely fail over the
long-term. Instead you should be looking toward discipline.&lt;/p&gt;

&lt;p&gt;There is a saying &lt;em&gt;&amp;quot;it takes 3 weeks for a new behavior to become
habit&amp;quot;&lt;/em&gt;. If you haven&amp;#39;t heard that before that&amp;#39;s OK because it isn&amp;#39;t
true. According to research it actually takes &lt;a href=&quot;http://www.huffingtonpost.com/james-clear/forming-new-habits_b_5104807.html&quot;&gt;on average 66 days of
continual behavior to form a
habit&lt;/a&gt;.
So ask yourself this. Can you use the same motivation for 66 days in a
row? If not, do you have that many different forms of motivation to form this
new habit over this period of time? I don&amp;#39;t think many of us do.&lt;/p&gt;

&lt;p&gt;Discipline on the otherhand is you saying to yourself &lt;em&gt;&amp;quot;I will do this
even if I would prefer to do something else&amp;quot;&lt;/em&gt;. It&amp;#39;s not an easy trait to
establish but if you can do so you&amp;#39;ll find that making changes happen
more easily. I think many of us have a &lt;em&gt;will&lt;/em&gt; to overcome existing habits and
form new ones but we lack the &lt;em&gt;way&lt;/em&gt; to do so. Too many distractions, too
many opportunities, too many excuses. Take a look at successful people
around you. Ask yourself are they successful because of some outside
motivation or are they successful because they&amp;#39;ve made a conscious
decision they&amp;#39;re going to wade through the muck to get what they want.&lt;/p&gt;

&lt;p&gt;Focus on being disciplined instead of waiting to be motivated. &lt;/p&gt;
</content>
  </entry><entry>
    <title>KSS Your Styleguide Goodbye</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/10/24/kss-your-styleguide" />
    <id>https://dockyard.com/blog/2014/10/24/kss-your-styleguide</id>
    <category term="web-development" label="Web Development"/><category term="tools" label="Tools"/><category term="process" label="Process"/>
    <published>2014-10-24 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Christopher Plummer</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Styleguides are a place where developers and designers can find authoritative information about how elements are to be styled throughout a project. Contributors can always refer to a styleguide to help them create new pages and elements. Careful attention to a styleguide can prevent a contributor from designing or developing components that don&amp;#39;t conform to the designers&amp;#39; vision.&lt;/p&gt;

&lt;p&gt;Most styleguides are created by designers and developers prior to development to guide the translation of comps into code. In a perfect world, that styleguide is a living document that is updated as changes are made to the design. This often doesn&amp;#39;t happen. As changes are made throughout a project&amp;#39;s development cycle, the styleguide is rarely updated. At some point on almost every project, that styleguide is no longer a reliable, authoritative document.&lt;/p&gt;

&lt;p&gt;If only there was a better way...&lt;/p&gt;

&lt;h2&gt;Enter KSS&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://warpspire.com/kss/&quot;&gt;KSS&lt;/a&gt; is a methodology and set of tools that will help you create automated, living styleguides. Through the KSS menting syntax and the KSS parser, the guide can be updated automatically throughout the development cycle. All those little adjustments and decisions that happen in conversations outside your documented channels will be reflected in your KSS styleguide. In theory, the styleguide will show the most up-to-date styles. KSS styleguides also render element states like &lt;code&gt;:hover&lt;/code&gt; as you can see in this &lt;a href=&quot;https://github.com/styleguide/css/&quot;&gt;example from GitHub&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/nfwgONd.jpg&quot; alt=&quot;GitHub Styleguide&quot;&gt;&lt;/p&gt;

&lt;p&gt;A KSS styleguide can be designed to reflect the look and layout of your project using existing styles:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/oq4P8vd.jpg&quot; alt=&quot;Two KSS Styleguides&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;KSS isn&amp;#39;t magic. It&amp;#39;s not going to create the styleguide for you.&lt;/strong&gt; You still have to do a lot of custom configuration and coding. Coding the styleguide starts with commenting your CSS. You have been leaving helpful comments for future developers all along, right? KSS &lt;a href=&quot;http://warpspire.com/kss/syntax/&quot;&gt;defines a syntax&lt;/a&gt; for these comments:&lt;/p&gt;
&lt;div class=&quot;highlight sass &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; Short description of the element to be documented&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;//&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; :hover             - description of this modifier.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; .disabled          - description of this state class modifier.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;//&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; Styleguide x.x.x. Section Name and/or Number&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;class&quot;&gt;.element-to-be-documented&lt;/span&gt; {
  ...
  &lt;span class=&quot;local-variable&quot;&gt;&amp;amp;&lt;/span&gt;:&lt;span class=&quot;value&quot;&gt;hover&lt;/span&gt;{
    ...
  }
  &lt;span class=&quot;local-variable&quot;&gt;&amp;amp;&lt;/span&gt;.&lt;span class=&quot;key&quot;&gt;disabled&lt;/span&gt;{
    ...
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A KSS parser like &lt;a href=&quot;https://github.com/kneath/kss&quot;&gt;this one for ruby&lt;/a&gt; parses the elements of those comments â the description, modifiers, and section â and applies it to a partial like this:&lt;/p&gt;
&lt;div class=&quot;highlight erb &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;styleguide-example&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;tag&quot;&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;instance-variable&quot;&gt;@section&lt;/span&gt;.section &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;styleguide-description markdown-body&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; markdown h(&lt;span class=&quot;instance-variable&quot;&gt;@section&lt;/span&gt;.description) &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;instance-variable&quot;&gt;@section&lt;/span&gt;.modifiers.any? &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;ul&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;styleguide-modifier&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%&lt;/span&gt; modifiers.each &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |modifier| &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; modifier.name &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt; - &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; modifier.description &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;styleguide-element&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;instance-variable&quot;&gt;@example_html&lt;/span&gt;.gsub(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;$modifier_class&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).html_safe &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%&lt;/span&gt; modifiers.each &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |modifier| &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;styleguide-element styleguide-modifier&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;styleguide-modifier-name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; modifier.name &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;instance-variable&quot;&gt;@example_html&lt;/span&gt;.gsub(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;$modifier_class&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;modifier.class_name&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html_safe &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;styleguide-html&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;instance-variable&quot;&gt;@example_html&lt;/span&gt; &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You&amp;#39;ll also need to create a controller, a template, helpers, and a front-end KSS script to render the styleguide. It&amp;#39;s a lot of up-front work, but there are examples and parsers already written for Node.js, Ruby, PHP, Sinatra, Rails, and so on.&lt;/p&gt;

&lt;h2&gt;Why use KSS?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If standards, methodolgies, and tools are your thing, you&amp;#39;ll like KSS:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The kss.js script can render elements with different states (called modifiers by KSS) directly in the styleguide blocks. For example, buttons with &lt;code&gt;:hover&lt;/code&gt;, &lt;code&gt;:focus&lt;/code&gt;, &lt;code&gt;:active&lt;/code&gt;, states or even modifier classes like &lt;code&gt;.red&lt;/code&gt;, &lt;code&gt;.is-active&lt;/code&gt;, or &lt;code&gt;.disabled&lt;/code&gt; will be automatically added to the styleguide allowing readers to see every possible state at once.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS comments and styleguide documentation are bound together in the stylesheets, not some other styleguide-specific template. UX developers can comment the stylesheets they work in most while they&amp;#39;re working in them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The styleguide templates can also include markup codeblocks, allowing readers to see the markup elements necessary to generate a component.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Why not use KSS?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If you&amp;#39;re in the &amp;quot;tools are bullshit&amp;quot; crowd, you&amp;#39;re going to hate KSS:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Styleguides created with KSS are only as reliable as the CSS and markup used to generate them. If an element is changed in a way that no longer conforms to the design comps, the styleguide will no longer reflect the correct way that element is supposed to be styled. For example, a developer might change the border radius of a particular button for a new page and doesn&amp;#39;t realize that he or she has just changed the base button style in the styleguide. Now the button entry styleguide is no longer a reliable representation of the styles established in the design comps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When elements are taken out of their context it can change how styles are applied. Elements have to be adjusted and changed just to appear correctly in the styleguide. This is work beyond what is strictly required to develop a site.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Styleguide-only styles and markup might be confusing to developers joining a project. The rules and markup in the styleguide aren&amp;#39;t necessarily the same rules or markup used in the site. When creating new elements that follow from a styleguide entry, simply copying the elements as they appear styleguide could cause layout and style problems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The KSS documention is spread out over many files. Nothing is centralized. Simply restructuring the styleguide, editing sections, or even adding new items requires sifting through many CSS files and templates. And when styles for elements are duplicated or spread across several pages, where do we put the documentation?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deciding what goes in the styleguide and how it is documented becomes another tangle of challenging questions. How do we describe this element? How to we organize the guide? What do we include?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;KSS Is Just Another Thing&lt;/h2&gt;

&lt;p&gt;The strength of KSS â automation â is also the source of its weakness â mutable elements. If the styleguide can be updated automatically, it can also be sabotaged accidentally. The styleguide must be QA&amp;#39;ed alongside the site to ensure that it conforms to the design comps and that it accurately illustrates elements as they appear in the actual site pages. Developers must take care to pay attention to styleguide-only rules and markup.&lt;/p&gt;

&lt;p&gt;You could generate a static styleguide in your comping tool of choice as a definitive reference against which to check the living styleguide. But then you&amp;#39;re just creating more documents that must be updated. You haven&amp;#39;t solved the original problem.&lt;/p&gt;

&lt;p&gt;Implementing KSS requires additional UX Development and Design resources (additional QA, more templates, styleguide-only styles, controllers, etc.), but may save resources spent creating and updating a static styleguide.&lt;/p&gt;

&lt;p&gt;KSS is not a perfect solution to the problem of maintaining living styleguides. You&amp;#39;ll simply have to try it in your workflow to evaluate its utility.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Go: UX East&#39;s UX Camp</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/09/24/announcing-ux-east-camp" />
    <id>https://dockyard.com/blog/2014/09/24/announcing-ux-east-camp</id>
    <category term="conferences" label="Conferences"/><category term="uxeast" label="Uxeast"/><category term="ux-east" label="Ux East"/><category term="design" label="Design"/><category term="design-process" label="Design Process"/><category term="design-thinking" label="Design Thinking"/>
    <published>2014-09-24 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>A weekend of creative thinking and collaboration.</summary>
    <content type="html">&lt;p&gt;We are pleased to announce &lt;a href=&quot;http://uxeast.org/&quot;&gt;UX East&amp;#39;s UX Camp&lt;/a&gt;, a weekend of creative thinking, collaboration, and design in one big house on Nov 14â16th in &lt;a href=&quot;https://goo.gl/maps/JPqdT&quot;&gt;Bryant Pond, ME&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This isn&amp;#39;t a typical networking event or conference. We&amp;#39;ll escape the busy and distracting city environment to focus on our craft alongside others interested in design. It&amp;#39;s a project weekend, a getaway, and a miniâconference all rolled into one. You&amp;#39;ll work on whatever you like with the option of gaining creative input of others.&lt;/p&gt;

&lt;p&gt;The environment is intimate by design. There will only be 30 people at this event who you&amp;#39;ll eat, sleep, and work alongside. On top of all this, there will be a workshop and a few talks available to all who attend.&lt;/p&gt;

&lt;p&gt;There are many more details to come, and I&amp;#39;m excited to share them with you! Follow our &lt;a href=&quot;https://twitter.com/ux_east&quot;&gt;UX East&lt;/a&gt; twitter account or check back here for updates. If you&amp;#39;re interested in taking part in the event in any capacity, please reach out to &lt;a href=&quot;mailTo:steven@dockyard.com&quot;&gt;steven@dockyard.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See you all in Maine!&lt;/p&gt;
</content>
  </entry><entry>
    <title>JavaScript Performance For The Win</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/09/22/javascript-performance-for-the-win" />
    <id>https://dockyard.com/blog/2014/09/22/javascript-performance-for-the-win</id>
    <category term="engineering" label="Engineering"/><category term="javascript" label="JavaScript"/>
    <published>2014-09-22 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Alex Navasardyan</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;JavaScript performance is a very hot topic nowadays. There&amp;#39;s a lot of information out there on what
browsers do with JavaScript code in order to execute it faster. Let&amp;#39;s go over some of the tips that
will help you write faster JavaScript code.&lt;/p&gt;

&lt;h2&gt;Tooling&lt;/h2&gt;

&lt;p&gt;There&amp;#39;re are couple of tools that you can use to identify and fix peformance problems. One of the
them is Chrome Developer Tools (open Chrome Developer Tools, switch to &lt;code&gt;Profiles&lt;/code&gt; tab and click &lt;code&gt;Start&lt;/code&gt;).
Developer Tools will give you a great overview of what actual happens in your application under the hood
(what functions are called, how much CPU time they consumed, how much memory). That&amp;#39;s a great starting
point. Now you can start fixing performance where it matters.&lt;/p&gt;

&lt;h2&gt;Non-optimizable code&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;try-catch&lt;/code&gt; and &lt;code&gt;try-finally&lt;/code&gt; blocks will not be optimized by the V8 (to be clear, if the function contains
a &lt;code&gt;try&lt;/code&gt; block, the whole function will not be optimized).&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// code&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;try&lt;/span&gt; {
  iMightThrowFunc();
} &lt;span class=&quot;keyword&quot;&gt;catch&lt;/span&gt;(exception) {
  iHandleExceptions(exception);
}
&lt;span class=&quot;comment&quot;&gt;// code&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A better way of writing the code above, would be to isolate the &lt;code&gt;try&lt;/code&gt; block into a separate function so &lt;code&gt;code&lt;/code&gt;
can be optimized and only &lt;code&gt;iMightThrowFunc&lt;/code&gt; would not be optimized:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;iMightThrow&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;try&lt;/span&gt; {
    &lt;span class=&quot;comment&quot;&gt;// [code]&lt;/span&gt;
  } &lt;span class=&quot;keyword&quot;&gt;catch&lt;/span&gt;(exception) {
    iHandleExceptions(exception);
  }
}

&lt;span class=&quot;comment&quot;&gt;// code&lt;/span&gt;
iMightThrow();
&lt;span class=&quot;comment&quot;&gt;// code&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Using Local Variables&lt;/h2&gt;

&lt;p&gt;If you&amp;#39;re using a piece of code many times, it&amp;#39;s better to create a local variable for it for a couple of reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;faster scope look ups (once the variable is local scope, it&amp;#39;s faster to retrieve it)&lt;/li&gt;
&lt;li&gt;caching (performing an operation once and storing the result will result in less work for the browser)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Literals&lt;/h2&gt;

&lt;p&gt;It might sound very obvious but you should use object literals whenever you can.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// use&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; array = [];
&lt;span class=&quot;comment&quot;&gt;// instead of&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; array = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Array(&lt;span class=&quot;integer&quot;&gt;16&lt;/span&gt;);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You rarely know what the size of the array is going to be in your application. Let V8 manage the growth
of the array as you add items to it. It will also ensure that the array is in &amp;quot;fast elements&amp;quot; mode and
item access is always fast. You can read more about V8 object representation &lt;a href=&quot;http://jayconrod.com/posts/52/a-tour-of-v8-object-representation&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;&amp;quot;Dictionary Mode&amp;quot;&lt;/h4&gt;

&lt;p&gt;An object will go into &amp;quot;dictionary mode&amp;quot; when you add too many properties dynamically
(outside constructor), &lt;code&gt;delete&lt;/code&gt; properties, use properties that cannot be valid identifiers.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;forInFunc&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; dictionary = {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;};
  &lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; key &lt;span class=&quot;keyword&quot;&gt;in&lt;/span&gt; dictionary);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you use an object as if it was a dictionary, it will be turned into a dictionary (hash table).
Passing such an object to for-in is a no no.&lt;/p&gt;

&lt;h4&gt;Iterating over a regular array&lt;/h4&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;arrayFunc&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; arr = [&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;];
  &lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; index &lt;span class=&quot;keyword&quot;&gt;in&lt;/span&gt; arr) {

  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Iterating over an array using &lt;code&gt;for-in&lt;/code&gt; is slower than a &lt;code&gt;for&lt;/code&gt; loop and the entire function containing
a &lt;code&gt;for-in&lt;/code&gt; statement will not be optimized.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;for&lt;/code&gt; loop is almost always a safe bet. Do you need to iterate over object&amp;#39;s properties?&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; objKeys = Object.keys(obj);
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; propertyName;

&lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;, l = objKeys.length; i &amp;lt; l; i++) {
  propertyName = objKeys[i];
  &lt;span class=&quot;comment&quot;&gt;// more code&lt;/span&gt;
}

&lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; propertyName &lt;span class=&quot;keyword&quot;&gt;in&lt;/span&gt; obj) {
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (obj.hasOwnProperty(propertyName)) {
    &lt;span class=&quot;comment&quot;&gt;// more code&lt;/span&gt;
  }
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;For-In&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;For-In&lt;/code&gt; statements can prevent the entire function from being optimized in a few cases. It will result
in &amp;quot;Not optimized: ForInStatement is not fast case&amp;quot; bailout.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;key&lt;/code&gt; has to be a pure local variable&lt;/h3&gt;

&lt;p&gt;It cannot be from upper scope or referenced from lower scope.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; key;

&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;doesNotSeemToBeLocalKey&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; obj = {};
  &lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (key &lt;span class=&quot;keyword&quot;&gt;in&lt;/span&gt; obj);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Arguments&lt;/h2&gt;

&lt;p&gt;Careless manipulations with &lt;code&gt;arguments&lt;/code&gt; might cause the whole function to be non-optimizable. It might result in
one of these &amp;quot;bailouts&amp;quot;: &amp;quot;Not optimized: Bad value context for arguments value&amp;quot; and &amp;quot;Not optimized: assignment
to parameter in arguments object&amp;quot;.&lt;/p&gt;

&lt;h3&gt;Reassigning &lt;code&gt;arguments&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// do not re-assign arguments&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;argumentsReassign&lt;/span&gt;(foo, bar) {
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (foo &amp;amp;&amp;amp; foo === &lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;) {
    bar = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Barracudas&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
  }
  &lt;span class=&quot;comment&quot;&gt;// code that uses `bar`&lt;/span&gt;
}

&lt;span class=&quot;comment&quot;&gt;// use local variables instead&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;argumentsReassign&lt;/span&gt;(foo, bar) {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; localBar;

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (foo &amp;amp;&amp;amp; foo === &lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;) {
    localBar = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Beantown Pub&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
  }
  &lt;span class=&quot;comment&quot;&gt;// code that uses `localBar`&lt;/span&gt;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Leaking &lt;code&gt;arguments&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// `arguments` is a special object and it is costly to materialize.&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;leaksArguments&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; args = [].slice.call(&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
  &lt;span class=&quot;comment&quot;&gt;// code that uses `args`&lt;/span&gt;
}

&lt;span class=&quot;comment&quot;&gt;// does not leak arguments&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;// accessing `arguments.length` is just an integer and doesn&#39;t materialize&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;// `arguments` object&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;doesNotLeakArguments&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; args = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Array(&lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;.length);

  &lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;; i &amp;lt; args.length; ++i) {
    &lt;span class=&quot;comment&quot;&gt;// `i` is always valid index in the arguments object&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// so we merely retrieve the value&lt;/span&gt;
    args[i] = &lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;[i];
  }
  &lt;span class=&quot;comment&quot;&gt;// code that uses `args`&lt;/span&gt;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note, that in most cases optimizing takes more code. You can probably write a build step for that:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;doesNotLeakArguments&lt;/span&gt;() {
  arguments_slice(args, &lt;span class=&quot;local-variable&quot;&gt;arguments&lt;/span&gt;);
  &lt;span class=&quot;comment&quot;&gt;// code that uses `args`&lt;/span&gt;
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Happy Coding!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building Quality Into Our Projects</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/09/19/building-quality-into-our-projects" />
    <id>https://dockyard.com/blog/2014/09/19/building-quality-into-our-projects</id>
    <category term="client" label="Client"/><category term="project-management" label="Project Management"/><category term="planning" label="Planning"/><category term="quality" label="Quality"/><category term="engineering" label="Engineering"/><category term="process" label="Process"/>
    <published>2014-09-19 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Jon Lacks</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;This article serves as a continuation of a âClient Targetedâ article recently published by our own Michael Dupuis (&lt;a href=&quot;http://reefpoints.dockyard.com/2014/09/12/features-as-business-objectives.html&quot;&gt;Features As Business Objectives&lt;/a&gt;). These posts aim to provide our current and prospective clients insight into how we approach development at DockYard.&lt;/p&gt;

&lt;p&gt;Building âQualityâ software does not happen by accident. It is actually one of the unspoken sides of the âiron triangleâ of project constraints (Scope, Cost, Time) - or should we call it a diamond now? Letâs not go there!
&lt;img src=&quot;http://i.imgur.com/DEWme3R.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;

&lt;p&gt;When making an investment in development of an application, the level of desired quality influences project cost and schedule.  Building an appropriate Quality Plan for a project requires time, planning and execution which is the responsibility of DockYard and the clients with whom we engage.  Below I layout the primary types of quality related practices we may consider applying to our (your) projects; always driven by clientsâ unique context (See my earlier blog post about context driving practices - &lt;a href=&quot;http://reefpoints.dockyard.com/2014/06/06/process-paradox.html&quot;&gt;Process Paradox&lt;/a&gt;).  This article does not serve to describe these quality practices in depth but will cover the basics in terms of how they could apply to client projects.  Any one of these practices in isolation is not an effective recipe for quality, it is the degree to which these practices are commingled in a logical way that results in positive outcomes.&lt;/p&gt;

&lt;h2&gt;Practice #1 - Test-Driven Development / Automated Testing&lt;/h2&gt;

&lt;p&gt;Before the Engineer writes a line of code they are investing time in thinking about and writing the appropriate test cases for the code - these tests will serve as a functional quality benchmark which the engineer can code towards. In parallel these efforts build up a library of automated tests that will ensure that the âworkingâ features built early in the project continue to work when new features (code) are introduced later on.  If we donât have these tests and we have 1000âs of lines of code, testing/debugging overhead raises exponentially which will result in increased risk to project cost and/or desired schedule.  Itâs also important to note that this practice is functionally-centric and not visual which is addressed with other practices described below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What this means to the client&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The cost and eventual savings related to this practice manifest themselves as time spent thinking vs. coding vs. testing. When we estimate what it will take to develop a given feature, we consider the time spent thinking about these tests, writing the tests, maintaining the tests in addition to writing the feature code.  However, keep in mind that the time spent testing later on in the project, when the code base has grown exponentially, is reduced due to this upfront investment of time (see figure below) because we have a growing set of automated tests that will ensure we continue to maintain high quality throughout the development cycle.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://imgur.com/2HBq9ie.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Practice #2 - Pair Programing / Code Reviews&lt;/h2&gt;

&lt;p&gt;Sometimes (usually) two heads are better than one.  Pair Programming is exactly as it is described. Two engineers team up to work side by side on a single unit of code (or feature.) In a 2013 article published by the Economist a study conducted by Laurie Williams of the University of Utah showed â&lt;em&gt;...paired programmers are 15% slower than two independent individual programmers, while &amp;quot;error-free&amp;quot; code increased from 70% to 85%. Since testing and debugging are often many times more costly than initial programming, this is an impressive result. Pairs typically consider more design alternatives than programmers working alone, and arrive at simpler, more maintainable designs; they also catch design defects early.&lt;/em&gt;â&lt;/p&gt;

&lt;p&gt;Additionally, Code Reviews by a peer or more senior engineer serve to ensure that the code being written meets agreed best practices and that mistakes of the past donât get reintroduced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What this means to the client&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pair programing and Code Reviews are practices DockYard believes yield higher quality code while also establishing a continuous learning culture across our engineering team.  The extent to which we apply these practices is less variable in that it is part of our company DNA - however, like any practice, a clientâs project context will dictate the extent to which these apply.  The client will incur the benefit of a well rounded and productive engineering team which can translate to reduced project cost.&lt;/p&gt;

&lt;h2&gt;Practice #3 - Manual Testing&lt;/h2&gt;

&lt;p&gt;In a literal sense this is the type of testing conducted by a human who seeks to ensure the less common use cases which may not have been exercised by an Automated Test or code review are working as expected. Additionally, this type of testing ensures the visual design of the product has been upheld -  Spacing, pixels, colors, fonts, etc.  Browser compatibility is also something manual testing will verify. This type of testing is usually conducted by members of the project team and the client. They work in collaboration across the feature set, report and classify severity of bugs which are eventually assigned to engineers when appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What this means to the client&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The client should be prepared to be a very active participant in this practice and schedule their time accordingly.  Feature complexity will drive the amount of time required for this type of testing - which might be nil if complexity is low.  A very rich user experience will require more testing and thus manifest itself in terms of increased time/cost.&lt;/p&gt;

&lt;h2&gt;Practice #4 - Client Demos (and Acceptance Testing)&lt;/h2&gt;

&lt;p&gt;For most projects we work in 1-2 week iterations (sprints) and at the conclusion of this time period we typically demonstrate the progress we have made by sharing working software. These demonstrations serve a dual purpose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;gives the client opportunity to verify development is proceeding in the desired direction, and if not, attempt to course correct early on vs. late in the project when course correction can be very costly&lt;/li&gt;
&lt;li&gt;allows the team to reflect and continuously improve how they are executing the project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When a feature is ready for prime time, we will usually ask the client to formally accept the feature as complete.  This ensures the team can shift their full focus and attention to building the next features on the backlog. Context switching can be very costly in terms of productivity, therefore we try to call things âDone Doneâ before moving on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What this means to the client&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similar to manual testing, client should be prepared to be a very active participant in both demos and conducting acceptance testing within agreed timeframes.  Deviation from established timeframes will result in increased project cost/time.  Therefore, whenever we engage with a client, we request upfront a high level of collaboration and availability to keep things moving along.&lt;/p&gt;

&lt;p&gt;Hopefully after reading this article, you have gained an appreciation for some of the considerations we make in terms building quality into our projects.  The level of quality a client desires and the pride DockYard has in its deliverables drives the extent to which these practices are utilized.  Therefore, if you are interested in engaging with us, think about the level of quality you expect and we will work together to derive an appropriate quality plan that balances your cost and time constraints.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Reducing Project Costs: Features As Business Objectives</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/09/12/features-as-business-objectives" />
    <id>https://dockyard.com/blog/2014/09/12/features-as-business-objectives</id>
    <category term="business" label="Business"/><category term="design-process" label="Design Process"/><category term="design-thinking" label="Design Thinking"/><category term="engineering" label="Engineering"/><category term="planning" label="Planning"/><category term="process" label="Process"/>
    <published>2014-09-12 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Michael Dupuis</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;There is a lot of insight a developer can offer when it comes to reducing costs associated with building web applications. While few developers have MBA degrees, we are âin the trenchesâ when it comes to bringing a project from &lt;a href=&quot;http://www.wikiwand.com/en/Ideation_(idea_generation)&quot;&gt;ideation&lt;/a&gt; to completion. We see where projects go astray and where in the process complexity gets introduced, timelines get pushed out, and costs rise.&lt;/p&gt;

&lt;p&gt;Failed features are a significant cost to any project. Iâm defining a failed feature as a feature which gets implemented by the developer correctly, but which was ill-conceived in the planning stages. Thereâs no 404 error pages, just poor user experiences that donât serve the applicationâs aim.&lt;/p&gt;

&lt;p&gt;To mitigate failed features, there is a first principle that I think clients should apply at the outset of any software project: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Align the applicationâs features with business goals.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;âHave attainable goals,â is something you hear in a range of industries â from fitness to financial planning. For example, it is common when designing an investment portfolio to come up with a baseline for what youâd like to have saved by the time you retire. Goals help quantify short-term success (meeting monthly savings goals) and bring context to immediate financial decisions (going on an extravagant vacation vs contributing to the 401k).&lt;/p&gt;

&lt;p&gt;In many regards, defining business goals is far harder than designing a feature for an application. Developers can implement an idea, but if the idea is not well grounded or refined enough, the implementation does not matter. Application consumers will not be able to use the feature in a way that translates to success for the business. For all intents and purposes, the feature is âbrokenâ and costs are about to go up because it will need to be fixed.&lt;/p&gt;

&lt;p&gt;This is why coming to a consultancy with a list of features is problematic. Features are not grounded in any sort of reasoning; business objectives are. Enter the planning process with a set of business objectives for the application.&lt;/p&gt;

&lt;p&gt;Letâs take a simple case. A client is overhauling their marketing site. They sit down in their first planning meeting with the designers and developers and say âwe want a blog.â A blog is a feature â it is not a business objective. What would be more helpful from the designer and developersâ perspectives is to hear: âwe want a way to show prospective clients that our firm is transparent.â This a business objective. It informs the designer that there is a target audience to design for (prospective clients). It tells the designer a little bit about the clientâs values (transparency). Yes, it may lead to a blog, but whatâs important is that it grounds the feature with a purpose.&lt;/p&gt;

&lt;p&gt;Features must align with business goals, because they create the theoretical framework in which the application operates; the alternative is an aimless application with a lot of code, a lot of options, and a lot of usability problems. Designing a user experience which gets the consumer from point A to point B becomes difficult because there is not a logical consistency to the elements in the application. Features do not have a unique roles, and so the designer cannot delegate responsibility in a predictable manner.&lt;/p&gt;

&lt;p&gt;Features that are not aligned with business objectives are expensive.&lt;/p&gt;

&lt;p&gt;It goes without saying, but clear design thinking translates into cleaner implementations for the developers building the application. Features can be added, removed, and enhanced without hurting other elements of the application. Code becomes less coupled, is more maintainable, and can be better tested.&lt;/p&gt;

&lt;p&gt;Features without well-defined roles donât have a place in the applicationâs ecosystem, and so they often fail. This is a worst case scenario. It means that users canât interact with the application in a way thatâs meaningful for the business. And since these failed features need to be fixed and re-worked to meet the business objective (which should have been known and communicated at the outset of the project âdiscoveryâ process), the client has expended the following resources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the time that went into designing and implementing the failed feature&lt;/li&gt;
&lt;li&gt;the cost that went into designing and implementing the failed feature&lt;/li&gt;
&lt;li&gt;the time that will go into designing and implementing the correct feature&lt;/li&gt;
&lt;li&gt;the cost that will go into designing and implementing the correct feature&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is to say nothing of the opportunity costs. While one client is figuring all of this out, a competitor who aligned their features with their business objectives and âgot it rightâ on the first attempt is gaining happy, new users. &lt;/p&gt;

&lt;p&gt;When a businesses hires a software consultancy to develop an application, theyâre bringing in skills and expertise from the outside. Itâs unlikely that a developer is going to advise a client on how to gain market share, and itâs just as unlikely that a client is going to open a designer/developerâs eyes to a new application feature. Rather than planning an application around a set of features, clients can make the most of a consultancy&amp;#39;s resources by coming to the planning stages of a project with well-defined business objectives.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Fear of Failure</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/09/11/fear-of-failure" />
    <id>https://dockyard.com/blog/2014/09/11/fear-of-failure</id>
    <category term="design-process" label="Design Process"/><category term="inspiration" label="Inspiration"/><category term="design-thinking" label="Design Thinking"/><category term="design" label="Design"/><category term="art" label="Art"/>
    <published>2014-09-11 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Logan Faerber</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;When confronted with a new task it&amp;#39;s natural for someone to feel a sense of anxious hesitation. Sure, it varies between individuals depending on the activity or setting, but entering an unfamiliar scenario can make anyone feel uncomfortable. Often this anxiety leads someone to succumb to their fears of failure, which ultimately results in them not even taking a chance at learning something new.&lt;/p&gt;

&lt;p&gt;No one wants to be a failure - there&amp;#39;s a connotation that you should just give up or else be publicly humiliated. Thanks to the recent development of social networks, anyone can declare someone as a failure simply by leaving a comment on a video online or posting blanketed statements on various articles - all the while never having to say it to their face directly or give useful constructive feedback. This mentality comes from a very judgmental and one sided declaration that spurs from people&amp;#39;s fear of being a failure themselves. &lt;/p&gt;

&lt;p&gt;Alone, the term failure is a simple solution to a more complex problem. It&amp;#39;s quick to label the scenario as everything having gone wrong rather than taking the time necessary to provide constructive feedback or to consider steps leading up to the &amp;quot;failure&amp;quot;. By neglecting to reflect on the the particulars of the situation we are not learning from our mis-steps. &lt;/p&gt;

&lt;p&gt;Rather than refer to these results as failures, I like to think of them as mistakes, granting more leniency to a lifetime of self-educating. While a failure feels conclusive, a mistake feels like a small part of a whole, which is more representative of how learning a new skill or concept should be. We should always be approaching the chance to learn something new with an optimistic and open mind, and the only way to do that successfully is to embrace the fact that you&amp;#39;re bound to make mistakes along the way. Think about it; if a kid messes up, we don&amp;#39;t instantly jump to calling them a failure. We let them know that it&amp;#39;s okay, they&amp;#39;ve made a mistake, but then we follow up with an instruction or demonstration on how they could improve next time. This ability to showcase compassion when sharing ideas is how we&amp;#39;ve come so far as a human race. We tend to be most curious as children because we&amp;#39;re unaware of the cultural judgment that comes from not being right all the time. We&amp;#39;re still willing to experiment without that fear of failure. The curiosity to learn something new is an exciting one, where we focus on ourselves improving and not the jealousy of what others have accomplished, so why not treat our entire lifetime of learning with a similar level of patience and understanding? &lt;/p&gt;

&lt;p&gt;Fear can be incredibly influential when learning something new as long as it&amp;#39;s used to fuel the fire and not extinguish it - prove it wrong. Instead of focusing on what you have to accomplish and getting overwhelmed, take time to learn at your own pace; as they say, patience is a virtue. The best way to learn is to dive right in without thinking too heavily. By getting directly involved you will be learning through a hands on experience, which helps to reconfirm what works and what doesn&amp;#39;t. As with most things, repetition is key to retaining information.  If you&amp;#39;re willing to make mistakes along the way, jump right in and get your hands dirty. Not only will you avoid wasting time hesitating, but you&amp;#39;re forced to find a solution now that you&amp;#39;ve already begun. The less you think in these scenarios, the better. &lt;/p&gt;

&lt;p&gt;In order to learn we must be willing to make mistakes. Hundreds if not thousands of them. You&amp;#39;ll probably even make some incredible, irreversible messes along the way. But rather than wasting time to criticize yourself or worry about what others think of you, focus on the task at hand. Take time to acknowledge what wasn&amp;#39;t working, why it wasn&amp;#39;t working, and move on. It&amp;#39;s as simple as that. Ultimately our biggest failures lead to our greatest successes. So in order for us to improve and grow as individuals as well as a society we must try to overcome this fear or else we&amp;#39;ll never progress, and that&amp;#39;s the real failure.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Comics and Big Data</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/08/25/design-and-big-data" />
    <id>https://dockyard.com/blog/2014/08/25/design-and-big-data</id>
    <category term="storytelling" label="Storytelling"/><category term="design" label="Design"/><category term="information-graphics" label="Information Graphics"/>
    <published>2014-08-25 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Ashley Treni</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Iâve never been into comics or graphic novels. Theyâve always remained in my periphery, but I never took the time to be interested in them. I appreciated good illustration, but rarely watched animations (except for Disney and Pixar of course) and pretty much ruled out that I would never âgetâ the appeal of a comic book.&lt;/p&gt;

&lt;p&gt;I took a data mining class last semester, and we discussed the importance of &lt;strong&gt;visual storytelling&lt;/strong&gt;. I jotted down notes and took away a comprehensive understanding of design implications - keep colors relative and consistent, scale, got it, check.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.northeastern.edu/camd/artdesign/people/dietmar-offenhuber/&quot;&gt;Dietmar&lt;/a&gt;, my professor, had mentioned a book by Scott McCloud, &lt;a href=&quot;http://scottmccloud.com/2-print/1-uc/&quot;&gt;Understanding Comics&lt;/a&gt;, and suggested looking to comics and film as an important metaphor for data visualization. Though I didnât pay much attention at the time, this notion stuck with me, and a few weeks ago I invested in that very book.&lt;/p&gt;

&lt;p&gt;Comics are a brilliant demonstration of visualizations that show multivariate information. Interactions, emotions, time, and space are all present, concurrent, and in flux - using frames and transitions to move the reader from one thought to the next. Comics pay attention to the readability of a story, by piecing together &amp;quot;juxtaposed images in deliberate sequence.&amp;quot; (McCloud, &lt;em&gt;Understanding Comics&lt;/em&gt;) Unlike film, however, the static nature of comics leaves room for creative challenges balancing those variables simultaneously, especially the evolution of time. &lt;/p&gt;

&lt;p&gt;A series of information graphics is subject to the same dimensional considerations. Data Visualization is a balance of data analytics, visual representations, and a narration which provides a context for each investigation. Designing complex data to be comprehensive, interactive, and inviting is quite a challenge. While there are tools we can use to inspire visualization methods and techniques, there is much more to consider. There is an entire science behind visual cognition; why humans respond to certain characteristics faster than others (to be elaborated on at another point in time).&lt;/p&gt;

&lt;p&gt;To incorporate storytelling into data visualization is to consider who we design for. Like comics, we must create an environment for the audience to become immersed, and the presentation of ideas shapes the interaction. The visual language we use, the way we sequence through visualizations, directly influences the legibility of the information. When we embrace the humanism of comprehension and perception, we design the experience to promote the success of the reader&amp;#39;s ability to understand.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s design to agitate curiosity and engagement. How can we utilize visual storytelling to inspire research, critical analysis, and conversation? Harnessing the power of design, we can draw inspiration from comics, and present information in a way that considers how the mind observes and acquires ideas.&lt;/p&gt;

&lt;p&gt;As it were, Iâm now devouring comics - making up for lost time. Iâve put my summer reading list on hold - to make time for books shared with me from fellow designers at DockYard, who maybe not so surprisingly, already have a deep appreciation and love for the brilliant medium that is comics.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Designing an Experience</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/08/22/design-an-experience" />
    <id>https://dockyard.com/blog/2014/08/22/design-an-experience</id>
    <category term="design-thinking" label="Design Thinking"/><category term="observations" label="Observations"/><category term="design" label="Design"/>
    <published>2014-08-22 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Tim Walsh</name></author>
    <summary>A parallel between live performance and experience design.</summary>
    <content type="html">&lt;p&gt;Over the years I have attended a lot of concerts, probably too many to count. Perhaps enough to make me deaf in the near future. One thing I&amp;#39;ve realized - I keep going back for the experience.&lt;/p&gt;

&lt;p&gt;A good concert is one where Iâve stood witness to the construction of a musical composition, built piece by piece from each member of the band, materializing into a single living, breathing entity; emblematic of those who devoted the time and energy into building something bigger than themselves. &lt;/p&gt;

&lt;p&gt;Good design should mirror this experience. It should be collaborative. It should be defiant and intelligent, original but cognisant of the past. It should set expectations for any and all future interactions. It should make the person say, ânow that was the best show Iâve ever been to.â &lt;/p&gt;

&lt;p&gt;Because when it comes down to it, who would want the alternative? A bad performance is like something designed in Microsoft Word. It is obvious and unbalanced. It is âtoo loudâ and often âhas way too many drunk people.â  &lt;/p&gt;

&lt;p&gt;So control the stage while designing. Give people an experience that not only captures their attention, but gives them a reason to listen.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The most difficult position to hire for in tech right now</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/08/06/the-most-difficult-position-to-hire-for-in-tech-right-now" />
    <id>https://dockyard.com/blog/2014/08/06/the-most-difficult-position-to-hire-for-in-tech-right-now</id>
    <category term="css" label="Css"/><category term="engineering" label="Engineering"/><category term="design" label="Design"/><category term="opinion" label="Opinion"/><category term="html" label="Html"/>
    <published>2014-08-06 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;The most difficult position to hire for in tech right now is not
engineering. It isn&amp;#39;t design. It is the hybrid position: the UX
developer. Or the UX designer. Or the implementation developer. Or the
CSS engineer.&lt;/p&gt;

&lt;p&gt;This is how difficult it is, I have no idea what the &amp;quot;official&amp;quot; title of
this position is. We seem to go back and forth every few weeks on what
to call it. But, this role has become incredibly crucial to how we and
most web companies operate.&lt;/p&gt;

&lt;p&gt;Historically the responsibility for this position has fallen to
engineering, or maybe design, depending upon how your team ran things.
And it was the worst work. Cutting HTML, building terrible CSS. But
today process and standards have fallen into place to make this role a
legitimate one that people should build a career in.&lt;/p&gt;

&lt;p&gt;Understanding how to optimize pages rendering, reduce CSS selector
lookups, organizing stylesheets and markup files. This is just the
start. Finding someone that can communicate between design and
engineering is a challenge and the people I&amp;#39;ve found to naturally fit
into this role excel at this. All of this before we ever start to talk
about accessibility, browser compatibility, standards compliance, and
responsive design.&lt;/p&gt;

&lt;p&gt;However, there is barely anyone out there making a career in this role.
Perhaps because it has been traditionally looked down upon. Or perhaps
because engineering and design get the glory. The UX developer might
think of one&amp;#39;s self as the red-headed-stepchild.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ve taken a lot of efforts to bring the same quality we have in
engineering and design here to our HTML &amp;amp; CSS. We&amp;#39;ve adopted
&lt;a href=&quot;http://bem.info/&quot;&gt;BEM&lt;/a&gt;,
&lt;a href=&quot;https://smacss.com/&quot;&gt;SMACSS&lt;/a&gt;, and we&amp;#39;re constantly looking to improve
our process and the tools we use. Have other companies found similar issues with this
growing field? I&amp;#39;d like to hear from some people.&lt;/p&gt;

&lt;p&gt;(btw &lt;a href=&quot;mailto:jobs@dockyard.com&quot;&gt;we&amp;#39;re hiring&lt;/a&gt;)&lt;/p&gt;
</content>
  </entry><entry>
    <title>Project Carpe Diem - &quot;Game Plan&quot;</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/07/29/project-carpe-diem" />
    <id>https://dockyard.com/blog/2014/07/29/project-carpe-diem</id>
    <category term="project-management" label="Project Management"/><category term="planning" label="Planning"/>
    <published>2014-07-29 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Jon Lacks</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;I have been exposed to many different work tracking/planning tools during my time as Project Manager. Early on it was tools like Excel, MS Project, IBM Rational. Later it was Jira, Kanban Boards, GitHub Issue Visualization Tools and physical PostIt Note boards. I would classify the former tools being more aligned with senior management&amp;#39;s desire to be âWell Informedâ and the latter being more team centric and aligned with Iterative software development. &lt;/p&gt;

&lt;p&gt;Working with both distributed and co-located teams has challenged me to devise appropriate work tracking strategies for these very different team contexts.  However, one thing has remained the same to this day: I have never worked with a team that has determined they do not want to do any level of work tracking either in a high or low fidelity way regardless of the software development methodology being applied.&lt;/p&gt;

&lt;p&gt;For purposes of this article I will be discussing some of the benefits we have seen in using a physical board with a couple of our co-located DockYard project teams. While I do maintain an appreciation of the big picture plan (aka High-Level Plan),  I have come to embrace a concept that is advocated in the field of Exercise Science - something I have been reading up on lately. I am sure this is not the only field of study citing this approach but wanted to mention this one as top of mind. It is the notion of setting smaller objectives to take one (us) closer to a larger goal. In terms of software development a goal would be synonymous with a product feature. By no means is this a new frontier in development planning, it is simply an application of some already acknowledged concepts.  What I believe is the slight twist is the setting of âDailyâ objectives  in addition to full Iteration objectives. Consider this Project Carpe Diem!&lt;/p&gt;

&lt;p&gt;At DockYard we are calling this approach âGame-Plan.â It covers the following four dimensions -&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Features&lt;/li&gt;
&lt;li&gt;Time (Days)&lt;/li&gt;
&lt;li&gt;Tasks (Hrs)&lt;/li&gt;
&lt;li&gt;Role on Team&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At DockYard we harnesses the power of the daily standup meeting with low tech multi-colored Post-It Notes on a physical board in the office.  During Iteration planning we discuss the next prioritized feature(s), lay out the relevant sub-features in agreeable sequence, define tasks for those sub-features across all the practice areas on our team. We set an estimation guardrail to have tasks be no smaller than half dayâs work and no larger than 2 - 3 days.  We discuss dependencies, hand offs, opportunities to parallelize (Optimize) work across different team members.  We start our iteration and reference the following board where we set/track daily team objectives - &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/hwZuLsa.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;

&lt;p&gt;At the conclusion of Iteration planning we take these tasks and convert them into GitHub issues aligned with a Milestone (Feature). However, we donât typically reference GH in our standup meetings but do see this as a very effective means to trace our code to the agreed tasks and enable a logical platform for code review.&lt;/p&gt;

&lt;p&gt;Other fringe benefits we are afforded by our âGame-Planâ on a daily basis include the following- &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clearly show dependencies across the team&lt;/li&gt;
&lt;li&gt;Helps us focus WIP (Work in Progress)&lt;/li&gt;
&lt;li&gt;Allows team to understand implications if a task is taking longer than expected - adjust our plan&lt;/li&gt;
&lt;li&gt;Allows us to suss out blockages that a team member might not reveal on their own &lt;/li&gt;
&lt;li&gt;If a team member has capacity and someone is over capacity they can see where they can help out &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will also note we do maintain visibility into the âHigh-Level Planâ at all times to ensure we continue to be thoughtful of implications to the overall project objectives.&lt;/p&gt;

&lt;p&gt;So Carpe Diem fellow Project Teams - Iâd love to hear if any teams out there are up to something similar or has learnings to share!&lt;/p&gt;
</content>
  </entry><entry>
    <title>On Selling UX</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/07/25/on-selling-ux" />
    <id>https://dockyard.com/blog/2014/07/25/on-selling-ux</id>
    <category term="design-thinking" label="Design Thinking"/><category term="design" label="Design"/><category term="design-process" label="Design Process"/>
    <published>2014-07-25 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>Getting what you want out of your design process.</summary>
    <content type="html">&lt;h2&gt;The Talk&lt;/h2&gt;

&lt;p&gt;People are talking about the difficulties of selling UX process to their boss, their clients, or their prospective clients. They&amp;#39;re upset that they don&amp;#39;t have the tools to create the caliber of experience others are building and it&amp;#39;s all because a few people aren&amp;#39;t buying into their process. You might have heard it or said it yourself that those in the way &amp;quot;just don&amp;#39;t get UX&amp;quot;. I know I&amp;#39;ve said it.&lt;/p&gt;

&lt;p&gt;From this point of view, we appear to be looking at the problem as a matter of conversion; turning someone who isn&amp;#39;t interested in change of process into someone who&amp;#39;ll embrace it. It&amp;#39;s a hard sell and, if you&amp;#39;ve ever experienced being hung up on while cold calling someone, you&amp;#39;ll know that your chances of failure are much greater than your chance of conversion. But don&amp;#39;t let that scare you.&lt;/p&gt;

&lt;p&gt;Just like the design process itself, there are many ways to approach this problem. Success in your approach is a matter of understanding perspective and - dare I say - empathy for those in the critical path.&lt;/p&gt;

&lt;h2&gt;Definitions&lt;/h2&gt;

&lt;p&gt;We all have a habit of creating definitions in our minds of what other people do from what we hear around the office (or internet) and they&amp;#39;re often pretty far off base. Those definitions become our foundation for what it means to be those other things: a designer, a developer, a product manager, a CEO. Those definitions, baseless or not, are used to judge the value of the things we do.&lt;/p&gt;

&lt;p&gt;An example might be that most people realize they need a software developer to build an application but they may not understand the angles to be considered, the processes for discovering those angles, or the costs involved. It&amp;#39;s easily misunderstood and can be a surprise for those outside of your industry.&lt;/p&gt;

&lt;h2&gt;Shared Values&lt;/h2&gt;

&lt;p&gt;We intend to create a great product and we understand there are many variations in process that could bring it to life. As creators, that process can often be poorly preconceived and unnecessarily limited before we get a hand in it. We have a few options from here to deliver our full value, and selling isn&amp;#39;t one of them.&lt;/p&gt;

&lt;p&gt;Aaron Scott from &lt;a href=&quot;http://leap.agency/&quot;&gt;Leap&lt;/a&gt; gave a talk at &lt;a href=&quot;http://www.meetup.com/uxboston/events/136304392/&quot;&gt;UX Boston Conf&lt;/a&gt; about doing your best in getting to know those you&amp;#39;re working with to help deliver a winning concept to the client. This approach holds true in more ways than just reaching a final design; it will help you gain the buy-in you need to perform at your full potential.&lt;/p&gt;

&lt;p&gt;The stakeholder may understand what you do, need some experience of your process before understanding, or maybe they&amp;#39;re not ready for it all. You need to know that they&amp;#39;re acting off of their definitions, and it&amp;#39;s not always their fault for having an incomplete picture. Just the same, it is equally important for us to understand them and their needs.&lt;/p&gt;

&lt;p&gt;If they&amp;#39;re not ready, convincing them otherwise will cause anxiety during the project and potentially cause issues of trust with you or future designers if things don&amp;#39;t go well. Use your best judgment and tread lightly.&lt;/p&gt;

&lt;h2&gt;Collaboration&lt;/h2&gt;

&lt;p&gt;When your work is primarily visual it can be especially difficult to get the buy in you need. Most of the stakeholders will have had vision for their entire lives and trust themselves to judge what they feel is good and bad. They have their own tastes, their own definitions of what you do, and their own expectations of the process.&lt;/p&gt;

&lt;p&gt;Our value as designers is best understood when demonstrated and this is your most powerful tool to gain buy in. Make room for them to be part of your design conversation. Problem solve and communicate with them like you might your design team. Let them breath the same air you are and replace your salesmanship with collaboration. Use this method instead of presentations and cold hard salesmanship or politics.&lt;/p&gt;

&lt;p&gt;If you don&amp;#39;t believe they&amp;#39;re a good fit to collaborate with your design team, you may wish to pass on their project. Consider them a &amp;quot;client in training&amp;quot;, give them your best advice, and set them free. Of course this isn&amp;#39;t as easy when working in-house, where I would hope that if you&amp;#39;ve come to this conclusion you&amp;#39;d start looking for a more collaborative environment.&lt;/p&gt;

&lt;p&gt;So stop &lt;em&gt;selling&lt;/em&gt; UX. Look around, listen, ask questions, and help the client in training see further before you put a contract in front of them. Your process of gaining an understanding of the product, users, and their context will sell your expertise all on its own. If they&amp;#39;re not ready, which is up to you to decide, set them free.&lt;/p&gt;

&lt;p&gt;They may not always be a returning client, but they will respect you for being honest with them every step of the way - and that&amp;#39;s a lifelong trust.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Making better repeat patterns</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/07/23/repeat-patterns" />
    <id>https://dockyard.com/blog/2014/07/23/repeat-patterns</id>
    <category term="experiments" label="Experiments"/><category term="design" label="Design"/>
    <published>2014-07-23 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>My favorite technique to avoid the obvious tiled look.</summary>
    <content type="html">&lt;p&gt;&lt;img class=&quot;illustration&quot; src=&quot;http://i.imgur.com/2GWB8Et.jpg&quot; alt=&quot;A most zen-like practice&quot;&gt;&lt;/p&gt;

&lt;p&gt;I enjoy the look of hand-drawn things. And I use patterns a lot. But when the two are combined, the results are often disappointing. My least favorite thing is to see a pattern where identical copies of a hand drawn object were repeated without variation. The automatic repetition here is not appropriate to the shaky handmade look of the art.&lt;/p&gt;

&lt;p&gt;The effect reminds me of Office circa 1995 (remember the classic marble and granite patterns?) or the obviously tiled walls in video game environments. In a 3D environment, a small size of the tile that causes this obvious tiled look is a necessity to conserve processing power.&lt;/p&gt;

&lt;p&gt;Remember these?
&lt;img src=&quot;https://i.imgur.com/jPzIWv8.jpg&quot; alt=&quot;bad textures&quot;&gt;&lt;/p&gt;

&lt;p&gt;Because I want to use hand drawn repeat patterns in my work, and it would be impractical to draw a thousand individual pieces to create the pattern, I experimented to determine exactly how many pieces I need to preserve the varied look, while being able to tile.&lt;/p&gt;

&lt;p&gt;When I intentionally draw similar objects, I found that 15-30 copies will make a decent repeat pattern. I draw more than I need, then squint and get rid of a few that are too dissimilar. Once pieces are arranged on the pattern, there will always be a few that stick out and attract attention to the âseamsâ between your pattern tiles. To solve this, I leave only a small amount of variation in both shape and placement, and I repeat a few of the shapes several times in a single tile. This distracts from the âedgesâ of the tiles because repetition happens on two different rhythms.&lt;/p&gt;

&lt;p&gt;Pattern element 2 is repeated several times within one unit.
&lt;img src=&quot;https://i.imgur.com/JDXVcVA.png&quot; alt=&quot;repeat pieces&quot;&gt;&lt;/p&gt;

&lt;p&gt;Trying to get as far away as I can from the obvious square tiled look, I also experimented with other manners of tiling. Adobe Illustrator offers brick (offset), hexagonal and other options, but I eventually need to go back to a rectangular repeating unit because I want to use my pattern in browsers.&lt;/p&gt;

&lt;p&gt;A rectangular repeat unit is used to make hexagonal tiles.
&lt;img src=&quot;https://i.imgur.com/gtEb7sn.png&quot; alt=&quot;repeat hex&quot;&gt;&lt;/p&gt;

&lt;p&gt;Here is one of the patterns I ended up making in this non-repeated style.&lt;/p&gt;

&lt;p&gt;One unit of the repeat pattern.
&lt;img src=&quot;https://i.imgur.com/HGzqiN5.png&quot; alt=&quot;trees&quot;&gt;&lt;/p&gt;

&lt;p&gt;I used this tree, circled, several times inside one repeating unit.
&lt;img src=&quot;https://i.imgur.com/tjduV4g.png&quot; alt=&quot;more trees&quot;&gt;&lt;/p&gt;

&lt;p&gt;The pieces are aligned to the grid, of course, but they are hand drawn so sizes are slightly off. I intentionally spaced them slightly off the grid as well, but preserved the overall balanced appearance (just squint and fix whatever looks off  - very scientific!)
&lt;img src=&quot;https://i.imgur.com/lgAlgpy.png&quot; alt=&quot;even more trees&quot;&gt;&lt;/p&gt;

&lt;h2&gt;And finally - here are the patterns!&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/jEK1YAq.png&quot; alt=&quot;swatches&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/patterns.ai&quot;&gt;Download the Illustrator file&lt;/a&gt; and use these patterns in any project. We only ask that you do not resell them. Enjoy!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Facebook Experiment</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/07/18/facebook-experimentation" />
    <id>https://dockyard.com/blog/2014/07/18/facebook-experimentation</id>
    <category term="experiments" label="Experiments"/><category term="advertising" label="Advertising"/>
    <published>2014-07-18 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>How I tried to experiment back on Facebook.</summary>
    <content type="html">&lt;p&gt;I just read this &lt;a href=&quot;https://medium.com/@scottrob/facebooks-going-to-be-ok-but-science-is-taking-a-hit-fd512b250f3e&quot;&gt;thoughtful and refreshing article&lt;/a&gt; about Facebook&amp;#39;s now infamous experiment on a large group of users. It outlines the ethical problems in running an experiment on unwilling participants, and how the scandal that followed damages the reputation of scientific research, which has ethical (not just legal) restrictions. It also reminds us that testing different versions of a product on users is nothing new, and we all seem OK with it as long as it stays in the realm of marketing.&lt;/p&gt;

&lt;p&gt;The outrage over users&amp;#39; emotions being manipulated without consent reminds me of my own feeling of insecurity a few years ago, when personalized ads just started appearing on Facebook (somewhere around 2009?). Suddenly this free service, which I use for talking to friends, is listening in and pushing ads on me. Weird. I wanted to push them back.&lt;/p&gt;

&lt;p&gt;Can I do anything to these algorithms that determine what ads I see? I wanted to experiment with them - to manipulate the ads by intentionally changing my information and posting fake content from my profile. I didn&amp;#39;t keep any screenshots for evidence, so you&amp;#39;ll just have to believe that some of it worked well.&lt;/p&gt;

&lt;p&gt;At the time, I had to use Facebook at work quite a lot. As &amp;quot;the web design person&amp;quot; for a nonprofit organization, I posted to Facebook regularly and kept track of potentially abusive comments on the official page, so I had to be logged in and therefore exposed to the ads at the same time.&lt;/p&gt;

&lt;p&gt;If you are a female - especially a female of an important purchasing age like me - you&amp;#39;ll have many companies fighting for your attention. In your early 20s it&amp;#39;s mostly personal purchases like shoes, clothes and makeup. A few years later, you qualify into the coveted &amp;quot;homemaker&amp;quot; target market. You supposedly start making decisions for a growing family about which groceries, appliances and brand of house paint to get - and companies really want your attention.&lt;/p&gt;

&lt;p&gt;I was getting tired of the keywords and browsing history from my personal life following me around at work with supposedly relevant shopping ads, so I tried to confuse Facebook. &lt;/p&gt;

&lt;p&gt;First I tried posting fake announcements of a tropical vacation and labeling some of my photos with far-away locations, but the ads didn&amp;#39;t change much. I would see the occasional 50% off ad for brand name luggage, but nothing drastic. Many of my Facebook friends were confused, including a few coworkers. (&amp;quot;A three week vacation? What about my report?&amp;quot;)&lt;/p&gt;

&lt;p&gt;Next, I changed my gender to male. I loved the ads that I got in return. Suddenly there were no glitter shoes, no 75% off designer dresses, no engagement rings. Instead I saw &amp;quot;finish your computer science degree&amp;quot;, high quality leather goods, and website hosting ads. I had not changed anything else about my behavior. The same keywords and likes give a girl and a boy version of me a completely different market persona. I enjoyed the boy version a lot more.&lt;/p&gt;

&lt;p&gt;The third thing I changed was location. Facebook seemed to save different location privacy settings on desktop and in the browser, and defaulted back to showing my location once in a while. I was not happy to reveal my exact location with each post. It just seemed too invasive. On top of that, Facebook started mining my friends&amp;#39; location settings to determine mine whether I wanted to reveal it or not. It seemed easier to claim a false location than to keep fighting for it to remain blank. I set my hometown and current location to North Pole, Alaska.&lt;/p&gt;

&lt;p&gt;The ads felt a bit more brawny on top of my previous change to &amp;quot;male&amp;quot;. Some offers of rugged hiking boots (I actually buy hiking boots!) and tactical something or other. On the downside, one real life friend later said she was confused by the  North Pole location.&lt;/p&gt;

&lt;p&gt;Since I tried those interventions, Facebook algorithms have of course advanced, and the simple gender setting change today might not produce a significant change in ads. But it felt rewarding to kick back at the marketing machine, and to sometimes get results. I am a web designer, so I have to be a user of web things as well as a maker. I do not think I will be quitting Facebook this week, or next. But I enjoy running experiments back on it.&lt;/p&gt;

&lt;p&gt;As a user, I was able to influence my ads. As a designer, I remain skeptical of user declared content. For example, if I had access to the kind of data Facebook has on most users, and wanted to target a person of a specific age and gender, I would consider their behavior instead of relying on one setting. I would look to confirm their gender, relationship status and age settings with specific keywords or themes in their posts and things they reacted to. &lt;/p&gt;

&lt;p&gt;We should make sure our products do not break in &amp;quot;weird&amp;quot; cases (for example, when user settings and behavior seemingly contradict each other), and remain aware of the assumptions we make in the design process.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Design as Conversation</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/07/18/design-as-conversation" />
    <id>https://dockyard.com/blog/2014/07/18/design-as-conversation</id>
    <category term="design" label="Design"/><category term="design-process" label="Design Process"/><category term="design-thinking" label="Design Thinking"/>
    <published>2014-07-18 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Ashley Treni</name></author>
    <summary>Invisible systems of the design process.</summary>
    <content type="html">&lt;p&gt;&lt;img class=&quot;illustration&quot; src=&quot;http://i.imgur.com/sxxEnba.jpg&quot; alt=&quot;Forest creatures of the Round Table&quot;&gt;&lt;/p&gt;

&lt;p&gt;Our understanding of design is perpetually in flux. Over the years design has transitioned from print and typography to web design, communication design to interaction design, user experience design to information design and design thinking. The space of design expands to encapsulate all these areas, while simultaneously formalizing specialized methodologies.&lt;/p&gt;

&lt;p&gt;Design is a process; it no longer refers only to static artifacts or visualizations. Design is a craft as much as it is a way of thinking and interacting.&lt;/p&gt;

&lt;p&gt;At DockYard, the design and development teams work closely together in an open dialogue, problem solving and giving real time feedback. Functionality and usability are built to work with one another, and it is this exchange of ideas, the conversation, that allows for the success of this interdisciplinary collaboration. There is no hierarchy of thought; each person brings personal experience and skill that contributes to a richer shared understanding. Many in the design world have begun to formalize this process - identifying these as environments for âinnovationâ.&lt;/p&gt;

&lt;p&gt;The success of design, however, doesnât lie in the adherence of these systems. As much as we may reflect on the process of design - it remains a real time activity. Visual design, UI/UX considerations, and software engineering are all skills that come second to the ability for a team to work together. Through conversation, articulation, and modeling, we design the way in which we confront social complexities and wicked problems that exist as a result of differing perspectives. DockYardâs internal process is sensitive to these considerations, but doesnât attempt to formalize its methodology, as problem solving is unique to each individual circumstance.&lt;/p&gt;

&lt;p&gt;The static, active, and meta states of design exist simultaneously layered within one another. When we invest in understanding one another, we truly embody what it means to design for experience, interaction, perception, emotion, and cognition. To âdesign the process of designâ is simply to be curious, present and engaged in all that we do.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.northeastern.edu/camd/artdesign/people/richard-saul-wurman/&quot;&gt;Richard Wurmanâs&lt;/a&gt; explicit philosophy resonates with me a great deal. His approach to life is a demand to embrace a lack of understanding; a mentality that allows you to ask questions, to start at the beginning. It liberates you to say &amp;quot;I don&amp;#39;t know what you mean&amp;quot; or &amp;quot;I don&amp;#39;t know much about that&amp;quot; - something we are unfortunately as a society not encouraged to do - much to the detriment of learning and individual understanding. These fears exist in work environments, classrooms, within relationships - we so often are made to feel inadequate if our understanding doesn&amp;#39;t match another&amp;#39;s (or our own) expectations.&lt;/p&gt;

&lt;p&gt;The collaborative nature of design reacts against these pressures. We each bring unique understanding, but it is our humility, interest in others and in experience, and the value we place in the exchange of ideas that makes design a powerful thing.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Macros for DRY and Testable Code</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/06/27/ember-macros-for-DRY-and-testable-code" />
    <id>https://dockyard.com/blog/2014/06/27/ember-macros-for-DRY-and-testable-code</id>
    <category term="best-practices" label="Best Practices"/><category term="ember" label="Ember.js"/><category term="testing" label="Testing"/>
    <published>2014-06-27 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Lin Reid</name></author>
    <summary></summary>
    <content type="html">&lt;h3&gt;Intro&lt;/h3&gt;

&lt;p&gt;This post in going to explore the idea of writing your own Ember macros
as a strategy for DRYing up and creating more modular Ember code. 
As you&amp;#39;ll see, besides the maintainability and flexibility benefits gained by DRYing
up and decoupling code, isolated code is significantly easier to test.
We&amp;#39;ll be using a sample application to illustrate refactoring some code
into a macro.&lt;/p&gt;

&lt;h3&gt;What is a Computed Property Macro?&lt;/h3&gt;

&lt;p&gt;A computed property macro can really be thought of as a function that returns the
definition of a computed property. Essentially, we are creating a function that will
define computed properties for us. They look something like this:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// Defining a computed property macro&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;greeting&lt;/span&gt;(dependentKey, greeting) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Ember.computed(dependentKey, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; greeting + &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; + dependentKey;
  });
}

&lt;span class=&quot;comment&quot;&gt;// Consuming a computed property macro&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Greeter = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;user&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;englishGreeting&lt;/span&gt;: greeting(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;spanishGreeting&lt;/span&gt;: greeting(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Hola&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; concierge = Greeter.create({ &lt;span class=&quot;key&quot;&gt;user&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Narwin&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; });
concierge.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;englishGreeting&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Hello, Narwin&#39;&lt;/span&gt;
concierge.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;spanishGreeting&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Hola, Narwin&#39;&lt;/span&gt;

concierge.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Boomer&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
concierge.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;englishGreeting&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Hello, Boomer&#39;&lt;/span&gt;
concierge.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;spanishGreeting&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Hola, Boomer&#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;So, why not just use a standard computed property? Macros give us the
ability to take common chunks of functionality and share them throughout
our code, allowing us to avoid re-writing the logic every time we need
it. &lt;/p&gt;

&lt;p&gt;Ember provides us with a bunch of useful computed macros
right out of the box. If you&amp;#39;re not familiar with them, you should
definitely &lt;a href=&quot;http://emberjs.com/api/#method_computed&quot;&gt;check them out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we&amp;#39;ve covered our bases, lets move on to the sample app.&lt;/p&gt;

&lt;h3&gt;Sample App&lt;/h3&gt;

&lt;p&gt;The goal of our sample application is to track financial transactions
and to provide an overview of income and expenses for a given time frame.
Our app has a &lt;code&gt;Month&lt;/code&gt; model which has many &lt;code&gt;transactions&lt;/code&gt;. A &lt;code&gt;Month&lt;/code&gt; also
has &lt;code&gt;incomeTransactions&lt;/code&gt; (transactions with positive amounts) and
&lt;code&gt;expenseTransactions&lt;/code&gt; (transactions with negative amounts). Below are
tests and code for our &lt;code&gt;Month&lt;/code&gt; and &lt;code&gt;Transaction&lt;/code&gt; models.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/models/month.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; hasMany = DS.hasMany;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; filter = Ember.computed.filter;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; DS.Model.extend({
  &lt;span class=&quot;key&quot;&gt;transactions&lt;/span&gt;: hasMany(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),

  &lt;span class=&quot;key&quot;&gt;incomeTransactions&lt;/span&gt;: filter(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(transaction) {
      &lt;span class=&quot;comment&quot;&gt;// Grab all transactions with a positive amount.&lt;/span&gt;
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; transaction.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &amp;gt; &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;;
    }
  ),

  &lt;span class=&quot;key&quot;&gt;expenseTransactions&lt;/span&gt;: filter(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(transaction) {
      &lt;span class=&quot;comment&quot;&gt;// Grab all transactions with a negative amount.&lt;/span&gt;
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; transaction.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &amp;lt; &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;;
    }
  )
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;tests/unit/models/month-test.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleForModel } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; store, month, transactions, tran1, tran2, tran3, tran4;

moduleForModel(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Unit - Month Model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;key&quot;&gt;needs&lt;/span&gt;: [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;model:transaction&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;],

  &lt;span class=&quot;function&quot;&gt;setup&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(container) {
    store = container.lookup(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;store:main&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

    month = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.subject({
      &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;June&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    });

    Ember.run(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
      tran1 = store.createRecord(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;100&lt;/span&gt; });
      tran2 = store.createRecord(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;200&lt;/span&gt; });
      tran3 = store.createRecord(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: -&lt;span class=&quot;integer&quot;&gt;300&lt;/span&gt; });
      tran4 = store.createRecord(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: -&lt;span class=&quot;integer&quot;&gt;400&lt;/span&gt; });

      transactions = [tran1, tran2, tran3, tran4];

      month.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).addObjects(transactions);
    });
  }
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTransactions returns positive transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; results = month.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  deepEqual(results, [tran1, tran2]);
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTransactions returns negative transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; results = month.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  deepEqual(results, [tran3, tran4]);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;app/models/transaction.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; attr = DS.attr;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; DS.Model.extend({
  &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The month controller will handle computing the &lt;code&gt;incomeTotal&lt;/code&gt; and
&lt;code&gt;expenseTotal&lt;/code&gt; for the month.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/controllers/month.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; computed = Ember.computed;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.ObjectController.extend({
  &lt;span class=&quot;key&quot;&gt;incomeTotal&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTransactions.[]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;comment&quot;&gt;// Get the amount for each transaction in incomeTransactions.&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; amounts = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).mapBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

    &lt;span class=&quot;comment&quot;&gt;// Sum the amounts&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; amounts.reduce(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(previousValue, currentValue) {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; previousValue += currentValue;
    }, &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;);
  }),

  &lt;span class=&quot;key&quot;&gt;expenseTotal&lt;/span&gt;: computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTransactions.[]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;comment&quot;&gt;// Get the amount for each transaction in expenseTransactions.&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; amounts = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).mapBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

    &lt;span class=&quot;comment&quot;&gt;// Sum the amounts&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; amounts.reduce(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(previousValue, currentValue) {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; previousValue += currentValue;
    }, &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;);
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;tests/unit/controllers/month-test.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
52
53
54
55
56
57
58
59
&lt;strong&gt;60&lt;/strong&gt;
61
62
63
64
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test, moduleFor } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; set = Ember.set;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; monthController, incomeTransactions, expenseTransactions;

moduleFor(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller:month&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Unit - Month Controller&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;setup&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    incomeTransactions = [
      { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;100&lt;/span&gt; },
      { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;200&lt;/span&gt; }
    ];

    expenseTransactions = [
      { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: -&lt;span class=&quot;integer&quot;&gt;300&lt;/span&gt; },
      { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: -&lt;span class=&quot;integer&quot;&gt;400&lt;/span&gt; }
    ];

    monthController = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.subject({
      &lt;span class=&quot;key&quot;&gt;incomeTransactions&lt;/span&gt;: incomeTransactions,
      &lt;span class=&quot;key&quot;&gt;expenseTransactions&lt;/span&gt;: expenseTransactions
    });
  }
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTotal returns the total of all incomeTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; result = monthController.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTotal&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  equal(result, &lt;span class=&quot;integer&quot;&gt;300&lt;/span&gt;);
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTotal recomputes when an incomeTransaction is added&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; newTransaction = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;500&lt;/span&gt; };

  monthController.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).addObject(newTransaction);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; result = monthController.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTotal&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  equal(result, &lt;span class=&quot;integer&quot;&gt;800&lt;/span&gt;);
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTotal returns the total of all expenseTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; result = monthController.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTotal&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  equal(result, -&lt;span class=&quot;integer&quot;&gt;700&lt;/span&gt;);
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTotal recomputes when an expenseTransaction is added&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; newTransaction = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: -&lt;span class=&quot;integer&quot;&gt;600&lt;/span&gt; };

  monthController.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).addObject(newTransaction);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; result = monthController.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTotal&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  equal(result, -&lt;span class=&quot;integer&quot;&gt;1300&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If your spidey senses are tingling, they should be. There is a lot of
duplication going on in above code. In fact, the only difference between &lt;code&gt;incomeTotal&lt;/code&gt; and
&lt;code&gt;expenseTotal&lt;/code&gt; is which set of transactions they are working with (incomeTransactions
or expenseTransactions). Similarly, the only difference between &lt;code&gt;incomeTransactions&lt;/code&gt; and &lt;code&gt;expenseTransactions&lt;/code&gt;
is whether the amount is a positive or negative number. Let&amp;#39;s write a couple of macros to DRY up this code.&lt;/p&gt;

&lt;h3&gt;Creating custom Ember Macros&lt;/h3&gt;

&lt;p&gt;Both &lt;code&gt;incomeTotal&lt;/code&gt; and &lt;code&gt;expenseTotal&lt;/code&gt; have almost exactly the same
logic. The goal of each is to take an array of objects and return the
sum of a specific property on each object. Let&amp;#39;s create a &lt;code&gt;sumBy&lt;/code&gt; macro
with the goal of being able to write something like: &lt;code&gt;sumBy(&amp;#39;array&amp;#39;, &amp;#39;property&amp;#39;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/utils/sum-by.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(collection, property) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Ember.reduceComputed(collection, {
    &lt;span class=&quot;key&quot;&gt;initialValue&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;0.0&lt;/span&gt;,

    &lt;span class=&quot;function&quot;&gt;addedItem&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(accumulatedValue, item){
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; accumulatedValue + Ember.get(item, property);
    },

    &lt;span class=&quot;function&quot;&gt;removedItem&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(accumulatedValue, item){
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; accumulatedValue - Ember.get(item, property);
    }
  });
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;tests/utils/sum-by.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; sumBy from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../../../utils/sum-by&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; set = Ember.set;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; bankAccount, transactions, tran1, tran2, tran3, tran4;

module(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Unit - SumBy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;setup&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    tran1 = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; };
    tran2 = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt; };
    tran3 = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt; };
    tran4 = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: -&lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt; };

    transactions = [tran1, tran2, tran3, tran4];

    bankAccount = Ember.Object.extend({
      &lt;span class=&quot;key&quot;&gt;transactions&lt;/span&gt;: transactions,
      &lt;span class=&quot;key&quot;&gt;totalAmount&lt;/span&gt;: sumBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    }).create();
  }
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns the sum of property for all objects in collection&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; actual = bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;totalAmount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  deepEqual(actual, &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;);
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;recomputes when a new object is added to the collection&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;);
  deepEqual(bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;totalAmount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;), &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;precondition&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; newTrans = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt; };

  bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).addObject(newTrans);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; actual = bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;totalAmount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);

  deepEqual(actual, &lt;span class=&quot;integer&quot;&gt;12&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;incomeTransactions&lt;/code&gt; and &lt;code&gt;expenseTransactions&lt;/code&gt; could also use some
DRYing up. The only difference between the two is whether they are
filtering by positive of negative numbers. Let&amp;#39;s write a &lt;code&gt;filterBySign&lt;/code&gt;
macro with the goal of being able to write something like: 
&lt;code&gt;filterBySign(&amp;#39;array&amp;#39;, &amp;#39;property&amp;#39;, &amp;#39;+&amp;#39;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/utils/filter-by-sign.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; get = Ember.get;
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; filter = Ember.computed.filter;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(collection, property, sign) {
  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; filter(collection, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(object) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; (sign + &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;) * get(object, property) &amp;gt; &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;;
  });
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;tests/unit/utils/filter-by-sign-test.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { test } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; filterBySign from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../../../utils/filter-by-sign&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; bankAccount, transactions, tran1, tran2, tran3, tran4;

module(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Unit - filterBySign&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;setup&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    tran1 = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; };
    tran2 = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt; };
    tran3 = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: -&lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt; };
    tran4 = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: -&lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt; };

    transactions = [tran1, tran2, tran3, tran4];

    bankAccount = Ember.Object.extend({
      &lt;span class=&quot;key&quot;&gt;transactions&lt;/span&gt;: transactions,
      &lt;span class=&quot;key&quot;&gt;positiveTransactions&lt;/span&gt;: filterBySign(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
      &lt;span class=&quot;key&quot;&gt;negativeTransactions&lt;/span&gt;: filterBySign(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    }).create();
  }
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;&#39;+&#39; returns all objects with positive property values&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; actual = bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;positiveTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; expected = [tran1, tran2];

  deepEqual(actual, expected);
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;&#39;-&#39; returns all objects with negative property values&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; actual = bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;negativeTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; expected = [tran3, tran4];

  deepEqual(actual, expected);
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;recomputes when a new object is added to the dependent array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  expect(&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;);
  deepEqual(bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;positiveTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;), [tran1, tran2]);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; newTrans = { &lt;span class=&quot;key&quot;&gt;amount&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1000&lt;/span&gt; };
  bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).addObject(newTrans);

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; actual = bankAccount.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;positiveTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; expected = [tran1, tran2, newTrans];

  deepEqual(actual, expected);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When reading through the tests for &lt;code&gt;filterBySign&lt;/code&gt;, note how much easier the setup is compared
to our original tests for the same functionality on the &lt;code&gt;Month&lt;/code&gt; model. Because
we&amp;#39;re testing the code in isolation, we&amp;#39;re able to use POJOs
and arrays to test our code. This allows us to avoid having to work
around the &lt;code&gt;Month&lt;/code&gt; model&amp;#39;s relationships, creating records with the
store and wrapping our setup code in an &lt;code&gt;Ember.run&lt;/code&gt; to handle async
behavior. Much nicer!&lt;/p&gt;

&lt;h3&gt;Refactoring the Month Model and Controller&lt;/h3&gt;

&lt;p&gt;We can now refactor our month model and controller to use our new
macros.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/model/month.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; filterBySign from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../utils/filter-by-sign&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; hasMany = DS.hasMany;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; DS.Model.extend({
  &lt;span class=&quot;key&quot;&gt;transactions&lt;/span&gt;: hasMany(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),

  &lt;span class=&quot;key&quot;&gt;incomeTransactions&lt;/span&gt;: filterBySign(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;expenseTransactions&lt;/span&gt;: filterBySign(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;app/controllers/month.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; sumBy from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../utils/sum-by&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.ObjectController.extend({
  &lt;span class=&quot;key&quot;&gt;incomeTotal&lt;/span&gt;: sumBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;incomeTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;expenseTotal&lt;/span&gt;: sumBy(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;expenseTransactions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The refactored model and controller are nice and concise while still
maintaining their readability. We can now delete our old unit tests on
our &lt;code&gt;Month&lt;/code&gt; model and controller as they now overlap with our macro tests.
The net result is trimming down the code we have to maintain by about
half.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;re thinking about writing a macro or just want to see what other macros
are out there, check out &lt;a href=&quot;https://github.com/jamesarosen/ember-cpm&quot;&gt;ember-cpm&lt;/a&gt;. 
It&amp;#39;s a library of non-core macros that you can plug in to you Ember app.
If you can&amp;#39;t find what you&amp;#39;re looking for there, take a shot at writing
your own macro and send in a pull request to share it with the
community!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Introducing Ember CLI Addons</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/06/24/introducing_ember_cli_addons" />
    <id>https://dockyard.com/blog/2014/06/24/introducing_ember_cli_addons</id>
    <category term="ember" label="Ember.js"/><category term="ember-cli" label="Ember-cli"/>
    <published>2014-06-24 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Robert Jackson</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;Distribution of reusable Ember.js libraries has been a pain point for quite a while. During application development we have frequently wished for a silver bullet for the sharing of concepts/code from one project to another.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/stefanpenner/ember-cli&quot;&gt;Ember CLI&lt;/a&gt; has given us the opportunity to set the conventions for sharing that we have been searching for.&lt;/p&gt;

&lt;p&gt;Over the last few weeks we have been focusing our efforts on the Ember CLI Addon story, and current support the following scenarios out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Performing operations on the &lt;code&gt;EmberApp&lt;/code&gt; created in the consuming applications &lt;code&gt;Brocfile.js&lt;/code&gt;. The most common things this would be used to call &lt;code&gt;app.import&lt;/code&gt; (see &lt;a href=&quot;http://iamstef.net/ember-cli/#managing-dependencies&quot;&gt;Ember CLI - Managing Dependencies&lt;/a&gt; for more details) or process the various options provided by the consuming application. Examples: &lt;a href=&quot;https://github.com/rwjblue/ember-cli-pretender&quot;&gt;ember-cli-pretender&lt;/a&gt;, &lt;a href=&quot;https://github.com/firebase/emberFire&quot;&gt;emberFire&lt;/a&gt;, and &lt;a href=&quot;https://github.com/rwjblue/ember-cli-ic-ajax&quot;&gt;ember-cli-ic-ajax&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding preprocessors to the default registry. This allows us to use a custom preprocessor to handle our templates, JavaScript, and/or styles. Example: &lt;a href=&quot;https://github.com/rwjblue/ember-cli-esnext&quot;&gt;ember-cli-esnext&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Providing a custom application tree to be merged with the consuming application. This allows you to distribute anything that might need to be imported in the consuming application; including components, templates, routes, mixins, helpers, etc. Example: &lt;a href=&quot;https://github.com/rondale-sc/ember-cli-super-number&quot;&gt;ember-cli-super-number&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Providing custom express middlewares. This allows for an addon to completely customize the development servers behaviors, making things like automated mock Ember Data API&amp;#39;s actually possible. This is currently only available on master (will be available in  0.0.37 and higher).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the design goals that the current crop of example addons follow is that they can all be installed and used simply via:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;npm install --save-dev &amp;lt;package name&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Details&lt;/h2&gt;

&lt;h3&gt;Discovery&lt;/h3&gt;

&lt;p&gt;Ember CLI detects the presence of an addon by inspecting each of your applications dependencies and searching their &lt;code&gt;package.json&lt;/code&gt; files for the presence of &lt;code&gt;ember-addon&lt;/code&gt; in the keywords section. &lt;/p&gt;

&lt;h3&gt;Creation&lt;/h3&gt;

&lt;p&gt;Once the available addons are detected, Ember CLI will require the addon.  By default it will use standard Node.js require rules (see &lt;a href=&quot;http://nodejs.org/api/modules.html#modules_all_together&quot;&gt;here&lt;/a&gt; for a breakdown), but you can provide a custom entry point by specifying a &lt;code&gt;ember-addon-main&lt;/code&gt; property in your &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Either way you go, during the various commands that cause a new build to be done (&lt;code&gt;ember server&lt;/code&gt;, &lt;code&gt;ember test&lt;/code&gt;, &lt;code&gt;ember build&lt;/code&gt;, etc) Ember CLI will create a new instance of the class that your addon returns passing it the &lt;code&gt;Project&lt;/code&gt; instance for the current project. The &lt;code&gt;Project&lt;/code&gt; model has a few functions that might be useful to your addon. You can see a full list by inspecting the &lt;a href=&quot;https://github.com/stefanpenner/ember-cli/blob/master/lib/models/project.js&quot;&gt;source&lt;/a&gt;, but to name a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;require&lt;/code&gt; -- Lets you require files or packages from the consuming application.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config&lt;/code&gt; -- Returns the configuration for the provided environment.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resolve&lt;/code&gt; -- Looks up a file from the root of the project using standard Node require semantics, but with the projects root as the base directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Build Process Inclusion&lt;/h3&gt;

&lt;p&gt;When the consuming application&amp;#39;s &lt;code&gt;Brocfile.js&lt;/code&gt; is processed by Ember CLI to build/serve/etc the addon&amp;#39;s &lt;code&gt;included&lt;/code&gt; function is called passing the &lt;code&gt;EmberApp&lt;/code&gt; instance. You can use this to access the options provided (for configuration of your addon for example).&lt;/p&gt;

&lt;h3&gt;Intra Build Hooks&lt;/h3&gt;

&lt;p&gt;There are a few other points in the build process that your addon can hook into via the &lt;code&gt;treeFor&lt;/code&gt; function. &lt;code&gt;treeFor&lt;/code&gt; is called to setup the final build output for a few specific points in the build process. The addons &lt;code&gt;treeFor&lt;/code&gt; function will be called with an argument that signifies which tree is being asked for.&lt;/p&gt;

&lt;p&gt;Currently, the following trees can be customized by the addon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;app&lt;/code&gt; -- The tree returned by your addon for the &lt;code&gt;app&lt;/code&gt; tree will be merged with that of the application. This is an excellent place to add custom initializers for your addon, add routes/controllers/views/components/templates/etc (anything that goes in &lt;code&gt;app/&lt;/code&gt; really). For additional information read through the &lt;a href=&quot;http://hashrocket.com/blog/posts/building-ember-addons&quot;&gt;blog post&lt;/a&gt; describing how &lt;code&gt;ember-cli-super-number&lt;/code&gt; was turned into an addon.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;styles&lt;/code&gt; -- The tree returned by your addon for the &lt;code&gt;styles&lt;/code&gt; tree will be merged with your applications styles (generally &lt;code&gt;app/styles/&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vendor&lt;/code&gt; -- The tree returned by your addon for the &lt;code&gt;vendor&lt;/code&gt; tree will be merged with your applications vendor tree (generally &lt;code&gt;vendor/&lt;/code&gt;). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the trees returned by addons are merged into the corresponding tree in the application. The application&amp;#39;s direct trees are always last so they will always override any files from an addon. This actually makes a wonderful place for application specific customization: your addon could provide a good default template, and the application can override by simply placing their own template in the same path.&lt;/p&gt;

&lt;h2&gt;Future&lt;/h2&gt;

&lt;p&gt;Many things are still planned for the &amp;quot;Addon Story&amp;quot; in Ember CLI. A few of them below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow addons to specify preferred ordering (before or after another addon). Similar in concept (and stolen from) the Ember initializer ordering. This is implemented on master and will be included in 0.0.37.&lt;/li&gt;
&lt;li&gt;Allow addons to provide a &lt;code&gt;blueprintPaths&lt;/code&gt; function that will return addition paths for blueprints to be looked up. This will allow an addon to override internal blueprints or add their own.&lt;/li&gt;
&lt;li&gt;Allow more than one preprocessor to be used at once. Currently, it is only possible to have a single preprocessor, but this is a limitation if you want both SCSS and plain CSS (for example).&lt;/li&gt;
&lt;li&gt;Expose post-processed stages. This will allow for better customization of the final output which things like &lt;a href=&quot;https://github.com/ai/autoprefixer&quot;&gt;autoprefixer&lt;/a&gt; would be able to take advantage of.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Call To Arms&lt;/h2&gt;

&lt;p&gt;This API is still very fluid and not set in stone. We need as much feedback as possible to truly solidify things.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Goodbye Heroku</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/06/23/goodbye-heroku" />
    <id>https://dockyard.com/blog/2014/06/23/goodbye-heroku</id>
    <category term="opinion" label="Opinion"/>
    <published>2014-06-23 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Done with them</summary>
    <content type="html">&lt;p&gt;I&amp;#39;ve been a Heroku user since the beginning. And I understand they have
had their ups and downs but over the past 2 years the service has been
degrading and today was the last straw for me. Allow me to elaborate.&lt;/p&gt;

&lt;h2&gt;Downtime&lt;/h2&gt;

&lt;p&gt;Today Heroku had a &amp;quot;Scheduled Maintenance at 2pm EST&amp;quot;. First of all,
this is just stupid. Don&amp;#39;t schedule a maintenance period at 2pm EST for
&lt;strong&gt;anything&lt;/strong&gt;. That period of time has to be one of the most heavily
trafficked timeslots on the web. Its an hour after everyone on the East
Coast has come back from lunch. It is an hour before lunch on the West
Coast. This, to me, demonstrates a lack of judgement on Heroku&amp;#39;s part. I
know the counter-argument is going to be &amp;quot;we&amp;#39;ve done plenty of other
scheduled maintenances at 2pm EST without incident&amp;quot;. My reply is that
this counter-argument is &lt;em&gt;bullshit&lt;/em&gt;. Just because you got away without
problems previously doesn&amp;#39;t mean they won&amp;#39;t happen in the future. Things
go wrong, people screw up. When Heroku has control over when those
screwups occur and they choose to push that risk at 2pm EST that is a
problem.&lt;/p&gt;

&lt;h2&gt;Reporting of Downtime&lt;/h2&gt;

&lt;p&gt;I am convinced their Status team just sits on Twitter all day and waits
for enough people to bitch and complain that Heroku is down before they
update the status page. I don&amp;#39;t care what data they provide to the
contrary. Why is the updated status page important? When our customers
email us during our vacation pissed off that we are not around and we
have &lt;em&gt;nothing&lt;/em&gt; to show to them to prove that this is Heroku&amp;#39;s fault and
not ours, to me that status page being updated immediately &lt;strong&gt;before&lt;/strong&gt;
our customers discover on their own is very important.&lt;/p&gt;

&lt;h2&gt;Price&lt;/h2&gt;

&lt;p&gt;It has been heavily reported that AWS has cut their pricing quite a bit
over the past few years. Yet, how many times has Heroku reduced its
price? (Heroku resells AWS) To my knowledge &lt;strong&gt;zero&lt;/strong&gt;. So everytime Amazon
reduces EC2 pricing Heroku just pockets the difference and gives a &amp;quot;fuck
you very much!&amp;quot; to all of its customers.&lt;/p&gt;

&lt;h2&gt;Fixes for All&lt;/h2&gt;

&lt;p&gt;The major downside to hosted devops is that when something goes wrong
that affects everyone you usually have to wait until they make the fix
for &lt;strong&gt;everyone&lt;/strong&gt; before your app comes back up. What should probably be
a 5 minute downtime &lt;em&gt;at most&lt;/em&gt; turns into a 30 minute downtime &lt;strong&gt;at least&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;Buildpacks&lt;/h2&gt;

&lt;p&gt;Buildpacks are just terrible.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I get that I&amp;#39;m ranting and I&amp;#39;m pretty pissed off. But mistakes like
today&amp;#39;s are completely avoidable yet Heroku chose to expose everyone to
this increased risk for no good reason that I can see.&lt;/p&gt;

&lt;p&gt;We will no longer be starting any new customers on Heroku. And we will
recommend to our current customers to move off of Heroku. We&amp;#39;re big fans
of Digital Ocean so we&amp;#39;re likely to land there as our preferred hosting
service.&lt;/p&gt;
</content>
  </entry><entry>
    <title>KAPOW! Writing prototypes with Framer</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/06/23/kapow-using-framer" />
    <id>https://dockyard.com/blog/2014/06/23/kapow-using-framer</id>
    <category term="prototyping" label="Prototyping"/><category term="design-process" label="Design Process"/><category term="design" label="Design"/>
    <published>2014-06-23 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>A look at Framer.js, a powerful prototyping tool.</summary>
    <content type="html">&lt;p&gt;I&amp;#39;ve finally used &lt;a href=&quot;http://framerjs.com/&quot;&gt;Framer&lt;/a&gt; on a client project and couldn&amp;#39;t be happier with the result. I normally use &lt;a href=&quot;http://www.invisionapp.com/&quot;&gt;InVision&lt;/a&gt; and highly recommend it, but Framer is the obvious choice when we need the experience to feel significantly more real.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.cooper.com/journal/2013/07/designers-toolkit-proto-testing-for-prototypes&quot;&gt;Every tool has its pros and cons&lt;/a&gt;, however, so it won&amp;#39;t &lt;em&gt;always&lt;/em&gt; be the best choice for you.&lt;/p&gt;

&lt;p&gt;Let me start with Framer&amp;#39;s big con: you must write JavaScript to knit a prototype together. The code itself is very easy to learn, but understanding how the Framer script interacts with your PSD&amp;#39;s groups and layer organization is like flying blind. With practice you can get past this and work gets much, much faster.&lt;/p&gt;

&lt;p&gt;The one other con is that their documentation is made more for developers than designers. So if you&amp;#39;re not used to digging into developer docs you will likely be overwhelmed and unsure what you&amp;#39;re looking for. Looking elsewhere won&amp;#39;t help you either, there doesn&amp;#39;t seem to be much community around this (yet).&lt;/p&gt;

&lt;p&gt;Someone with less coding experience will find Framer difficult and more intimidating than it has to be. I&amp;#39;d recommend dealing with the learning curve by practicing on a few side projects before you put anything important on the line (not that side projects aren&amp;#39;t important).&lt;/p&gt;

&lt;p&gt;Where Framer really shines bright: you won&amp;#39;t have to verbalize (or make embarrassing gestures) for how your app should feel, because you define that with enormous control. Oddly enough, the biggest con is your ally here, as writing custom JavaScript is what makes this control possible.&lt;/p&gt;

&lt;p&gt;Framer supports clicks and taps just the same, supports many animation options, is highly configurable, and runs very, very smoothly on all (of my) devices. I&amp;#39;ve tested it on iPhone, iPad, and a Mac. Because of this control and variability of use, your prototypes will feel much more real to the user in a testing scenario. This is especially good when your interactions help communicate state and position.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;ve used Framer before, let me know how you like it. There&amp;#39;s only so much time in the world to play with prototyping tools, but my next experiment will be with &lt;a href=&quot;http://facebook.github.io/origami/&quot;&gt;Origami&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Bonus!&lt;/h2&gt;

&lt;p&gt;While doing user testing sessions, you may want the testee to work on the actual device. To do so you can use &lt;a href=&quot;http://anvilformac.com/&quot;&gt;Anvil&lt;/a&gt; to create a local web address using &lt;a href=&quot;http://pow.cx/&quot;&gt;Pow&lt;/a&gt;. This will give you an address (something like &lt;code&gt;http://yourappname.youripaddress.xip.io/&lt;/code&gt;) that you may access on your device.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Making the DIY conference badges</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/06/21/making-the-diy-badges" />
    <id>https://dockyard.com/blog/2014/06/21/making-the-diy-badges</id>
    <category term="diy" label="DIY"/><category term="conferences" label="Conferences"/><category term="events" label="Events"/><category term="design" label="Design"/>
    <published>2014-06-21 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>What are badges for, anyway?</summary>
    <content type="html">&lt;p&gt;What are badges for, anyway? At any professional event with more than fifteen people, we wear some sort of name tag.&lt;/p&gt;

&lt;h2&gt;The current situation with badges:&lt;/h2&gt;

&lt;p&gt;If it&amp;#39;s a smaller or low budget event, you get a shipping label and write your name with a sharpie, then stick to your shirt and hope it holds. (I always stick mine to a pant leg just because.) &lt;/p&gt;

&lt;p&gt;A step up would be vinyl stickers or shipping labels with something like the conference name printed on them, but again attendees must write their name. &lt;/p&gt;

&lt;p&gt;At the highest level of badge, you arrive an event and receive a fully branded badge on a colorful lanyard with your name and photo printed on both sides, to prevent you from lending your $800 conference pass to a friend.&lt;/p&gt;

&lt;h2&gt;Three things badges do best:&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Prove that you&amp;#39;ve paid for your ticket&lt;/li&gt;
&lt;li&gt;Help brand the event&lt;/li&gt;
&lt;li&gt;Help you meet people&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our focus for the badges was mostly to help people meet and talk, and if we get to show off the Wicked Good Conferences brand - that&amp;#39;s cool too. We did not rely on the badges for ticketing because the event is relatively small, and held in a single location. There were no repeated check-ins at the door or strangers walking in off the relatively low traffic street.&lt;/p&gt;

&lt;p&gt;This allowed me the freedom to experiment with the badges. The only restriction was the budget; we wanted to make about 200 customizable name badges with a budget range of $20â$50. This is not a realistic budget for high quality &amp;quot;professionally&amp;quot; printed badges (decent custom lanyards alone are at least $1 each).&lt;/p&gt;

&lt;h2&gt;No printed names&lt;/h2&gt;

&lt;p&gt;We decided to skip printing people&amp;#39;s names altogether, and ask them to write names instead. This also allowed people to put a twitter handle and other useful information on the badges, and be funny with them. I am an introvert, so I appreciate any excuse to start a conversation. Stickers, twitter handles and stick figures on badges helped make interaction easier.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/UgBuSJx.jpg&quot; alt=&quot;Badges&quot;&gt;&lt;/p&gt;

&lt;h2&gt;No printed lanyards&lt;/h2&gt;

&lt;p&gt;Custom printed lanyards, in the quality we wanted, were way above our budget. Instead, we tried a few DIY ideas: string, ribbon, rope and strips of jersey fabric. The fabric turned out to be the most comfortable to wear. Knit jersey (&amp;quot;tee-shirt&amp;quot;) fabric will roll into a soft string if you cut 1&amp;quot; wide strips and stretch them out. We used about 2.5 yards of 52&amp;quot; wide fabric to make the 200 strips. We could make the strips a half to a third of the width of the fabric, depending on how long we wanted the strips to be.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/lRjE1Tf.jpg&quot; alt=&quot;Supplies&quot;&gt;&lt;/p&gt;

&lt;p&gt;An added benefit of using fabric is a much better selection of colors compared to lanyards. We managed to get a near-perfect match to our attendee shirts!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://imgur.com/tMhxpV7.jpg&quot; alt=&quot;Matched colors&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Actually, no printed anything&lt;/h2&gt;

&lt;p&gt;To make a color impression at a low cost we used a rubber stamp with a purple ink pad. We did not commit to placing any sponsor logos on the badges, so I had complete freedom with this design. We ordered a rubber stamp of the Wicked Good Conferences logo by itself so we can reuse it for the next conferences. To make the badge itself, we stamped and punched a hole in standard 3Ã5&amp;quot; index cards.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/Iai4JJ4.jpg&quot; alt=&quot;Stamping...&quot;&gt;
&lt;img src=&quot;https://i.imgur.com/OrrtLlj.jpg&quot; alt=&quot;Stamped!&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Budget breakdown&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1Ã2&amp;quot; Custom rubber stamp&amp;quot;: $12 + shipping&lt;/li&gt;
&lt;li&gt;Purple ink pad: $3.50&lt;/li&gt;
&lt;li&gt;Index cards, 2 packs of 100: ~$7&lt;/li&gt;
&lt;li&gt;Single hole punch: ~$5&lt;/li&gt;
&lt;li&gt;Jersey fabric (we already had it, but if you need to buy it cost about $5/yard): free or $15&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Lessons learned&lt;/h2&gt;

&lt;p&gt;The badges felt about right for the event, not too formal, not too shabby. Some lanyards turned out a bit short, but people were creative with placement, wearing them not only around the neck but on a sleeve, on the hat, tying them to the belt loop or a shirt button, and even wearing as a soft choker.
Next time around we can also experiment with other paper types and have the paper cut to size, to allow for a sturdier badge in a wider range of colors.&lt;/p&gt;

&lt;p&gt;Were you at WGE? Let us know what you thought of the DIY badges!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Swift and JavaScript</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/06/15/swift-and-javascript" />
    <id>https://dockyard.com/blog/2014/06/15/swift-and-javascript</id>
    <category term="javascript" label="JavaScript"/><category term="swift" label="Swift"/>
    <published>2014-06-15 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Alex Navasardyan</name></author>
    <summary>Swift explained for JavaScript developers</summary>
    <content type="html">&lt;p&gt;You might have already heard about a new language from Apple, &lt;a href=&quot;https://developer.apple.com/swift/&quot;&gt;Swift&lt;/a&gt;.
If you haven&amp;#39;t, make sure to check it out. This is the language that is going to replace &lt;a href=&quot;https://en.wikipedia.org/wiki/Objective-C&quot;&gt;Objective-C&lt;/a&gt; in the future.&lt;/p&gt;

&lt;p&gt;So why should a JavaScript developer be excited about a language like Swift?
Because semicolons are optional in Swift, too.&lt;/p&gt;

&lt;h3&gt;Variables&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s declare a variable in &lt;code&gt;JavaScript&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; country = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Argentina&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here&amp;#39;s how the same declaration looks like in Swift:&lt;/p&gt;
&lt;div class=&quot;highlight swift &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;var country: String = &amp;quot;Argentina&amp;quot;;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;However, the same statement can be rewritten as such:&lt;/p&gt;
&lt;div class=&quot;highlight swift &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;var country = &amp;quot;Argentina&amp;quot;; // inferred as String
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Swift uses type inference. It looks on the right hand side of the assignment
to figure out the type of the variable.&lt;/p&gt;

&lt;p&gt;Swift is type safe language. It performs type checks during compilation time
and informs you if there are any type mismatch errors. Unlike in JavaScript,
that means that after you defined &lt;code&gt;country&lt;/code&gt; variable and its type was
inferred to be &lt;code&gt;String&lt;/code&gt;, you can&amp;#39;t re-assign with another type:&lt;/p&gt;
&lt;div class=&quot;highlight swift &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;country = 2; // Cannot convert the expression&#39;s type to type &#39;String&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Constants&lt;/h3&gt;

&lt;p&gt;JavaScript doesn&amp;#39;t have a concept of a &lt;code&gt;constant&lt;/code&gt;. All &amp;quot;constants&amp;quot; are just
variables (typically in the outer scope). You can &amp;quot;freeze&amp;quot; the object using
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze&quot;&gt;Object.freeze()&lt;/a&gt;
to prevent new properties to be added and existing properties to be removed.&lt;/p&gt;

&lt;p&gt;The next version of JavaScript is going to introduce &lt;a href=&quot;https://people.mozilla.org/%7Ejorendorff/es6-draft.html#sec-13.2.1&quot;&gt;const&lt;/a&gt;
keyword and will support constants:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;const y = &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;; &lt;span class=&quot;comment&quot;&gt;// Note that you need to specift the value of the constant&lt;/span&gt;
y = &lt;span class=&quot;integer&quot;&gt;20&lt;/span&gt;;       &lt;span class=&quot;comment&quot;&gt;// SyntaxError: Assignment to constant variable&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you want to define a constant in Swift, you will use &lt;code&gt;let&lt;/code&gt; keyword:&lt;/p&gt;
&lt;div class=&quot;highlight swift &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let bestCity = &amp;quot;Boston&amp;quot;;
bestCity = &amp;quot;Cape Town&amp;quot;; // Cannot assign to &#39;let&#39; value &#39;bestCity&#39;

// Swift allows you to use underscore as a delimiter
// to improve readability of your code
let oneMillion = 1_000_000;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Tuples&lt;/h3&gt;

&lt;p&gt;So what is a &lt;a href=&quot;http://en.wikipedia.org/wiki/Tuple&quot;&gt;tuple&lt;/a&gt;? TL;DR it&amp;#39;s an ordered list of things.&lt;/p&gt;

&lt;p&gt;You can think of a tuple as if it&amp;#39;s an object:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; villain = {
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;:     &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Magneto&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;realName&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Max Eisenhardt&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;powers&lt;/span&gt;:   [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Magnetic flight&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Magnetic force fields&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;]
};

villain.name; &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Magneto&#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In Swift, the declaration of a tuple will look like this:&lt;/p&gt;
&lt;div class=&quot;highlight swift &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;let villain = (
  name:     &amp;quot;Magneto&amp;quot;,
  realName: &amp;quot;Max Eisenhardt&amp;quot;,
  powers:   [&amp;quot;Magnetic flight&amp;quot;, &amp;quot;Magnetic force fields&amp;quot;]
);

villain.name; // =&amp;gt; &amp;quot;Magneto&amp;quot;
villain.1;    // =&amp;gt; &amp;quot;Max Eisenhardt&amp;quot;
villain.2;    // =&amp;gt; [...]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Tuples are useful when you want to return multiple values from a function as a single compound value (that is
exactly what we do so often in JavaScript).&lt;/p&gt;

&lt;h3&gt;Arrays and Dictionaries&lt;/h3&gt;

&lt;p&gt;Definining an array or a dictionary looks very similar.&lt;/p&gt;

&lt;p&gt;In JavaScript:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; names = [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Alex&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Rob&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Dan&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;];
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; ages  = { &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Alex&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;13&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Rob&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Dan&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt; };

names[&lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;];     &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; &#39;Alex&#39;&lt;/span&gt;
ages[&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Alex&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;]; &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; 13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In Swift:&lt;/p&gt;
&lt;div class=&quot;highlight swift &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;var names = [&amp;quot;Alex&amp;quot;, &amp;quot;Rob&amp;quot;, &amp;quot;Dan&amp;quot;];
var ages  = [&amp;quot;Alex&amp;quot;: 13, &amp;quot;Rob&amp;quot;: 5, &amp;quot;Dan&amp;quot;: 4];

names[0];     // =&amp;gt; &amp;quot;Alex&amp;quot;
ages[&amp;quot;Alex&amp;quot;]; // 13
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Generics&lt;/h3&gt;

&lt;p&gt;In a very generic, hand wavy terms &lt;code&gt;Generics&lt;/code&gt; introduce type safety and reusability of the code. They&amp;#39;re frequently used
in classes and methods that operate on them.&lt;/p&gt;

&lt;p&gt;To illustrate what &lt;code&gt;Generics&lt;/code&gt; are, let&amp;#39;s implement a &lt;a href=&quot;https://en.wikipedia.org/wiki/Queue_(abstract_data_type)&quot;&gt;&lt;code&gt;Queue&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;Queue&lt;/span&gt;() {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._queue = [];
}

Queue.prototype.&lt;span class=&quot;function&quot;&gt;enqueue&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(item) {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._queue.push(item);
}

Queue.prototype.&lt;span class=&quot;function&quot;&gt;dequeue&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
 &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._queue.shift();
}

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; queue = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Queue();

queue.enqueue(&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;);
queue.enqueue(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
queue.enqueue(&lt;span class=&quot;float&quot;&gt;0.5&lt;/span&gt;);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now wasn&amp;#39;t that easy, eh?&lt;/p&gt;

&lt;p&gt;Note, that you don&amp;#39;t have to care about types in JavaScript that much. You just &lt;code&gt;enqueue&lt;/code&gt; a value of any type
and you&amp;#39;re all set.&lt;/p&gt;

&lt;p&gt;Swift is different. You can&amp;#39;t push objects of different types onto the array.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s a &lt;code&gt;Queue&lt;/code&gt; class for &lt;code&gt;Integer&lt;/code&gt; values:&lt;/p&gt;
&lt;div class=&quot;highlight swift &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;class Queue {
  var _queue = Int[]();

  func enqueue(item: Int) {
    _queue.append(item);
  }

  func dequeue() -&amp;gt; Int {
    return _queue.removeAtIndex(0);
  }
}

var queue = Queue();

queue.enqueue(2);
queue.enqueue(3);
queue.enqueue(4);
queue.enqueue(&amp;quot;4&amp;quot;); // Cannot convert the expression&#39;s type to type &#39;Int&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;What if you want to create a &lt;code&gt;Queue&lt;/code&gt; class for &lt;code&gt;String&lt;/code&gt; values? You&amp;#39;re going to have copy implementation of &lt;code&gt;Queue&amp;lt;Int&amp;gt;&lt;/code&gt; class
and replace &lt;code&gt;Int&lt;/code&gt; with &lt;code&gt;String&lt;/code&gt;. A lot of code duplication. Here&amp;#39;s where &lt;code&gt;Generics&lt;/code&gt; shine.&lt;/p&gt;
&lt;div class=&quot;highlight swift &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;class Queue&amp;lt;T&amp;gt; {
  var _queue = T[]();

  func enqueue(item: T) {
    _queue.append(item);
  }

  func dequeue() -&amp;gt; T {
    return _queue.removeAtIndex(0);
  }
}

var intQueue    = Queue&amp;lt;Int&amp;gt;();
var stringQueue = Queue&amp;lt;String&amp;gt;();

intQueue.enqueue(2);
intQueue.enqueue(3);
intQueue.enqueue(4);

stringQueue.enqueue(&amp;quot;2&amp;quot;);
stringQueue.enqueue(&amp;quot;3&amp;quot;);
stringQueue.enqueue(&amp;quot;4&amp;quot;);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now you can create &lt;code&gt;Queue&lt;/code&gt; of the different types with just one &lt;code&gt;Queue&lt;/code&gt; implementation.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Swift is a step in the right direction in my opinion. They lowered the &amp;quot;language ramp up&amp;quot; time by simplifying Objective-C syntax
quite a bit without damaging the power of the language. I feel like it looks really compelling to JavaScript developers.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The Process Paradox</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/06/06/process-paradox" />
    <id>https://dockyard.com/blog/2014/06/06/process-paradox</id>
    <category term="agile" label="Agile"/><category term="process" label="Process"/>
    <published>2014-06-06 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Jon Lacks</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;If it feels like process, it is not workingâ¦ It should feel like a logical means to achieve an end.&lt;/p&gt;

&lt;p&gt;For much of my career as a Project Manager I have been inundated with software development process, theories, techniques, methodologies and related tools - which by association has trickled into the teams I have worked with.  Over time I have observed team members feeling the frustration that âProcessâ can bring to a project when it is applied in a theoretical way vs. a practical way.  Have you ever facilitated a planning meeting while team members glaze over and bury their heads into their laptops? To all my Project Management brethren - if this is something you are observing in your teams, donât accept this reality; realize that your process &amp;quot;is not working&amp;quot;.&lt;/p&gt;

&lt;p&gt;The art of project management is not dictating process but finding practices that align with the teamâs needs and context.   For purposes of this blog post these are the âlogical meansâ I refer to in my opening statement above.  A little Scrum here, a little Waterfall there, and a sprinkle of Kanban might be the right recipe for a particular project - whereas it could be totally wrong for another.   &lt;/p&gt;

&lt;p&gt;In many ways this context is driven by the pyramid of constraints - cost/scope/time, which is project management 101.  However, other contexts might be size of team, remote/co-located, green-field development, team member experience, criticality of deliverables to human life, number of stakeholders, thick/thin management hierarchy, complexity of business rules/logic, and many others which are industry specific.  &lt;/p&gt;

&lt;p&gt;One of my biggest gripes with the âAgileâ movement is that companies/teams are adopting variations of the methodology as a prescription to execute projects. I am pretty damn sure the pioneering thinkers who wrote the Agile Manifesto wanted teams to become more principled in thinking about the practices they chose to use vs. following the playbook blindly and not making sure it aligns with the project context.&lt;/p&gt;

&lt;p&gt;It has been very affirming to know that engineers and designers in large and small companies loath process â Iâd say this is pretty universal. However, I have found that these same people are incredibly logical people who are willing to do something non-engineering/design related if  they feel deep down it is a âlogical means to achieve an end.â I believe it is the project managerâs responsibility as a servant leader to make sure teams donât feel like process is holding them back but that it is helping them move forward.&lt;/p&gt;

&lt;p&gt;What I love about being a Project Manager at DockYard is the diversity of the project contexts that come through our door. For me it is and has been a great way to experiment, mix, and match processes to find the right practices for a team/project context.  I believe that DockYardâs acknowledgment of this reality allows us to better serve our clientsâ unique contexts.  Not by accident - it is a very deliberate way to approach projects and one size never fits all.   &lt;/p&gt;
</content>
  </entry><entry>
    <title>Building an Ember App with Rails Part 4</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/31/building-an-ember-app-with-rails-part-4" />
    <id>https://dockyard.com/blog/2014/05/31/building-an-ember-app-with-rails-part-4</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="ember" label="Ember.js"/>
    <published>2014-05-31 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;em&gt;This is a four-part series:
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/07/building-an-ember-app-with-rails-part-1.html&quot;&gt;Part 1&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/08/building-an-ember-app-with-rails-part-2.html&quot;&gt;Part 2&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/09/building-an-ember-app-with-rails-part-3.html&quot;&gt;Part 3&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/31/building-an-ember-app-with-rails-part-4.html&quot;&gt;Part 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before we get underway we need to update ember-data in our project to at
least &lt;code&gt;1.0.0-beta.8&lt;/code&gt;. Open &lt;code&gt;ember/bower.json&lt;/code&gt; and if you have any version
less than 8 you&amp;#39;ll need to update to at least 8. If you are already on 8
or higher you won&amp;#39;t need to do anything.&lt;/p&gt;

&lt;p&gt;Once you&amp;#39;ve made the change save the file and run &lt;code&gt;bower install&lt;/code&gt; from
the &lt;code&gt;ember/&lt;/code&gt; directory. If you are asked to choose between different
versions of ember-data make sure you choose the correct one.&lt;/p&gt;

&lt;p&gt;In this part we&amp;#39;ll add Presentations to each of the Speaker pages. This
means we&amp;#39;ll have to add a relationship between two models.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;ember/tests/integration/speakers-page-test.js&lt;/code&gt; modify the test
&amp;quot;Should list all speakers and number of presentations&amp;quot;&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/tests/integration/speaker-page-test.js&lt;/span&gt;

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should list all speakers and number of presentations&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Bugs Bunny (2)&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Wile E. Coyote (1)&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Yosemite Sam (3)&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The number in the parentheses will represent the number of presentations that this speaker 
has given.&lt;/p&gt;

&lt;p&gt;Next we need to modify our &lt;code&gt;beforeEach&lt;/code&gt; function&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/tests/integration/speaker-page-test.js&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; speakers = [
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bugs Bunny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;presentation_ids&lt;/span&gt;: [&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;] },
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Wile E. Coyote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;presentation_ids&lt;/span&gt;: [&lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;] },
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Yosemite Sam&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;presentation_ids&lt;/span&gt;: [&lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;6&lt;/span&gt;] }
];

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; presentations = [
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;What&#39;s up with Docs?&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;speaker_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; },
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Of course, you know, this means war.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;speaker_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; },
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Getting the most from the Acme categlog.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;speaker_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt; },
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Shaaaad up!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;speaker_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt; },
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Ah hates rabbits.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;speaker_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt; },
  { &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;The Great horni-todes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;speaker_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt; }
];

server = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Pretender(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/api/speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(request) {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; [&lt;span class=&quot;integer&quot;&gt;200&lt;/span&gt;, {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}, JSON.stringify({&lt;span class=&quot;key&quot;&gt;speakers&lt;/span&gt;: speakers, &lt;span class=&quot;key&quot;&gt;presentations&lt;/span&gt;: presentations})];
  });

  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/api/speakers/:id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(request) {
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; speaker = speakers.find(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(speaker) {
      &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (speaker.id === parseInt(request.params.id, &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;)) {
        &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; speaker;
      }
    });

    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; [&lt;span class=&quot;integer&quot;&gt;200&lt;/span&gt;, {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}, JSON.stringify({&lt;span class=&quot;key&quot;&gt;speaker&lt;/span&gt;: speaker, &lt;span class=&quot;key&quot;&gt;presentations&lt;/span&gt;: presentations})];
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Completely replace the &lt;code&gt;speakers&lt;/code&gt; variable that was previously there. The only change to the API stub is that
&lt;code&gt;presentations&lt;/code&gt; is being added to the payload. The JSON here is the
style of JSON that ember-data expects to be emitted. We are returning a
payload that includes all speakers and presentations. The speaker
records include ids referencing the presentations associated.&lt;/p&gt;

&lt;p&gt;We can now add the Presentation model to our Ember app:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/models/presentation.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; DS from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; DS.Model.extend({
  &lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: DS.attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;speaker&lt;/span&gt;: DS.belongsTo(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;speaker&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
}); 
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We&amp;#39;ve told ember-data to expect the Presentation model to belong to the
Speaker model. Let&amp;#39;s set the inverse relationship&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/models/speaker.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; DS from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; DS.Model.extend({
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: DS.attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;key&quot;&gt;presentations&lt;/span&gt;: DS.hasMany(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;presentation&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Modifying our existing Speaker model to add to relationship to its many
Presentation models.&lt;/p&gt;

&lt;p&gt;Finally to make this tests green we need to change our template:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;// ember/app/templates/speakers/index.hbs

&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;link-to&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;speakers.show&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
   &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; (&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;presentations.length&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;)
 &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;link-to&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice that we we can call regular JavaScript properties like &lt;code&gt;length&lt;/code&gt; on the association.
There is also a slight change that I&amp;#39;ve made to the &lt;code&gt;link-to&lt;/code&gt;. Adding
&lt;code&gt;~&lt;/code&gt; will &lt;a href=&quot;http://handlebarsjs.com/block_helpers.html#whitespace-control&quot;&gt;tell Handlebars how to control
whitespace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this point our new test should be green. Lets add another.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/tests/integration/speaker-page-test.js&lt;/span&gt;

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should list all presentations for a speaker&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/speakers/1&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;li:contains(&amp;quot;What&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;s up with Docs?&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;li:contains(&amp;quot;Of course, you know, this means war.&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This new test is asserting that when we visit a given speaker&amp;#39;s page all
of those speaker&amp;#39;s presentations will be listed. We first need to add
presentation data to the API stub (within our &lt;code&gt;beforeEach&lt;/code&gt; function) for visiting a speaker page.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/tests/integration/speaker-page-test.js&lt;/span&gt;

&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/api/speakers/:id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(request) {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; speaker = speakers.find(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(speaker) {
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (speaker.id === parseInt(request.params.id, &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;)) {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; speaker;
    }
  });

  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; speakerPresentations = presentations.filter(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(presentation) {
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (presentation.speaker_id === speaker.id) {
      &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;;
    }
  });

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; [&lt;span class=&quot;integer&quot;&gt;200&lt;/span&gt;, {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}, JSON.stringify({&lt;span class=&quot;key&quot;&gt;speaker&lt;/span&gt;: speaker, &lt;span class=&quot;key&quot;&gt;presentations&lt;/span&gt;: speakerPresentations})];
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This modification of the previously existing stub will build a new payload object that
includes the speaker matching the id requested and all of the
presentations specific to that speaker.&lt;/p&gt;

&lt;p&gt;Tying up this test is easy now, we just modify the Speaker&amp;#39;s &lt;code&gt;show&lt;/code&gt;
template:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;h4&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Presentations&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;presentations&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now that we have a green test suite with our mocked out API let&amp;#39;s add the
real Rails endpoint. We&amp;#39;ll start by generating a new Presentation model.
Change to the &lt;code&gt;rails/&lt;/code&gt; directory in your project and run &lt;code&gt;rails generate
model presentation title:string speaker_id:integer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next we&amp;#39;ll generate the serializer: &lt;code&gt;rails generate serializer
presentation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s expand upon the &lt;code&gt;rails/db/seeds.rb&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# rails/db/seeds.rb&lt;/span&gt;

bugs = &lt;span class=&quot;constant&quot;&gt;Speaker&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bug Bunny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
wile = &lt;span class=&quot;constant&quot;&gt;Speaker&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Wile E. Coyote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
sam  = &lt;span class=&quot;constant&quot;&gt;Speaker&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Yosemite Sam&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)

bugs.presentations.create(&lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;What&#39;s up with Docs?&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
bugs.presentations.create(&lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Of course, you know, this means war.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)

wile.presentations.create(&lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Getting the most from the Acme categlog.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)

sam.presentations.create(&lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Shaaaad up!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
sam.presentations.create(&lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Ah hates rabbits.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
sam.presentations.create(&lt;span class=&quot;key&quot;&gt;title&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;The Great horni-todes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Tell our &lt;code&gt;Speaker&lt;/code&gt; model that there is a relationship to &lt;code&gt;Presentation&lt;/code&gt;
models:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# rails/app/models/speaker.rb&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Speaker&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  has_many &lt;span class=&quot;symbol&quot;&gt;:presentations&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Finally we need to modify the serializers.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# rails/app/serializers/presentation_serializer.rb&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;PresentationSerializer&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveModel&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Serializer&lt;/span&gt;
  attributes &lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:title&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# rails/app/serializers/speaker_serializer.rb&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;SpeakerSerializer&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveModel&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Serializer&lt;/span&gt;
  embed &lt;span class=&quot;symbol&quot;&gt;:ids&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;include&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;

  attributes &lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;
  has_many &lt;span class=&quot;symbol&quot;&gt;:presentations&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the &lt;code&gt;SpeakerSerializer&lt;/code&gt; we have instructed the serializer to include
the associated &lt;code&gt;Presentation&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s reset the database and re-seed &lt;code&gt;rake db:drop db:create db:migrate db:seed&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Make sure you are running your Ember server with the proxy enabled:
&lt;code&gt;ember server --proxy http://localhost:3000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now you can hit your application and you should have a all of the
necessary data. &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/jmHGxgS.png&quot; alt=&quot;image1&quot;&gt;
&lt;img src=&quot;http://i.imgur.com/plrKLvg.png&quot; alt=&quot;image2&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bostonember/website/commit/10f838ff1bfb0aa1307d4de6587889489697c8da&quot;&gt;Check out the actual code for this
part&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Avoid Rails When Generating JSON responses with PostgreSQL</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/27/avoid-rails-when-generating-json-responses-with-postgresql" />
    <id>https://dockyard.com/blog/2014/05/27/avoid-rails-when-generating-json-responses-with-postgresql</id>
    <category term="postgresql" label="PostgreSQL"/><category term="postgres_ext" label="Postgres_ext"/><category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2014-05-27 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Let&#39;s use PostgreSQL instead of Ruby to generate JSON responses</summary>
    <content type="html">&lt;p&gt;What if I told you that you could generate the following JSON response
in PostgreSQL?&lt;/p&gt;
&lt;div class=&quot;highlight json &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;{
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:[
    {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Tag #0&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;},
    {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;1001&lt;/span&gt;,&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Tag #1000&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;},
    {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;2001&lt;/span&gt;,&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Tag #2000&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;},
    &lt;span class=&quot;error&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;.&lt;/span&gt;
  ],
  &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:[
    {
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Note #0&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Lorem ipsum...&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:[&lt;span class=&quot;integer&quot;&gt;9001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;8001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;7001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;6001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;5001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;4001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;3001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;2001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;1001&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;]
    },
    {
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Note #1&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Lorem ipsum...&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;:[&lt;span class=&quot;integer&quot;&gt;9002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;8002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;7002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;6002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;5002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;4002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;3002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;2002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;1002&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;]
    }
  ]
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;What if I told you that it is over 10X faster than plain &lt;a href=&quot;https://github.com/rails-api/active_model_serializers/&quot;&gt;ActiveModel::Serializers&lt;/a&gt;
for small data sets, and 160X faster for larger data sets?&lt;/p&gt;

&lt;p&gt;Typically when you have an API serving up JSON responses, your web
framework serializes your data after retrieving it with its ORM. We&amp;#39;ll
talk about Rails specifically in this article, but this will generally
apply to most frameworks. So the typical Rails request will roughly
follow this flow (I am purposely brushing over some parts of the request
response cycle):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rails receives the JSON request from the browser/client&lt;/li&gt;
&lt;li&gt;Rails will apply some business logic and craft a query via
 ActiveRecord&lt;/li&gt;
&lt;li&gt;ActiveRecord serializes its query and sends the query to PostgreSQL&lt;/li&gt;
&lt;li&gt;PostgreSQL will compile the result set and serializes the records
 in its protocol format&lt;/li&gt;
&lt;li&gt;ActiveRecord deserializes the records into a set of rows object&lt;/li&gt;
&lt;li&gt;ActiveRecord will convert the set of rows into a set of model
 object instances&lt;/li&gt;
&lt;li&gt;Rails will convert the set of models objects into a JSON string&lt;/li&gt;
&lt;li&gt;Rails will send the JSON string down to the browser&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most of the time in this response cycle is spent in steps 6 and 7. Rails
has to deserialize one format, then store that deserialized content in
memory just to serialize it in a different format. Since &lt;a href=&quot;http://www.postgresql.org/docs/current/static/datatype-json.html&quot;&gt;PostgreSQL
supports JSON responses&lt;/a&gt;,
we can use its &lt;a href=&quot;http://www.postgresql.org/docs/current/static/functions-json.html&quot;&gt;JSON functions&lt;/a&gt; to
serialized our result set. That JSON response will still be serialized
in PostgreSQL&amp;#39;s protocol format, but ActiveRecord can deserialize it as
a single string object, instead of a set of objects which it then
converts and reserializes. We end up having this response cycle instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rails receives the JSON request from the browser/client&lt;/li&gt;
&lt;li&gt;Rails will apply some business logic and craft a query via
 ActiveRecord&lt;/li&gt;
&lt;li&gt;ActiveRecord serializes its query and sends the query to PostgreSQL&lt;/li&gt;
&lt;li&gt;PostgreSQL will compile the result set, serializes it as JSON then 
 serializes the JSON in its protocol format&lt;/li&gt;
&lt;li&gt;ActiveRecord deserializes the protocal format into a single JSON
 string&lt;/li&gt;
&lt;li&gt;Rails will send the JSON string down to the browser&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are only removing 2 steps, but it is the bulk of the time spent
generating the response. We are also limiting the number of ruby objects
created, so this reduces memory usage and time spent garbage collecting
short lived Ruby objects used only for JSONification.&lt;/p&gt;

&lt;h1&gt;What Do We Gain by Generating Massive Queries for PostgreSQL&lt;/h1&gt;

&lt;p&gt;It takes a lot of work to tell PostgreSQL to generate a specific
JSON object; what exactly does that buy us?
By doing all this in PostgreSQL, we avoid using CPU cycles
and memory on our web server. I&amp;#39;ve done some very naive and basic
testing with a new, unoptimized Rails project, and a database of 1000
notes, each have 10 unique tags, totalling 10000 tags. When retrieving
all 11000 records with Rails and &lt;a href=&quot;https://github.com/rails-api/active_model_serializers&quot;&gt;ActiveModel::Serializers&lt;/a&gt;, it took
roughly 9 seconds to generate the request. Most of the time was spent
in the View generating the JSON object in memory, with 657 milliseconds
in ActiveRecord, which (I think until someone tells me otherwise)
includes creating all the model instances.&lt;/p&gt;

&lt;p&gt;When we apply the PostgreSQL technique outlined later in this article to the
same result set, the response only takes 72 milliseconds for the first
request. If we rerun this same request, PostgreSQL caching kicks in and
the response time is 54 milliseconds. That is a &lt;strong&gt;~160X&lt;/strong&gt; throughput
increase when we use PostgreSQL to generate JSON payloads.&lt;/p&gt;

&lt;p&gt;The above numbers are a bit skewed by the size of this test payload.
11000 objects would be completely crazy to present to an end user. If we
pare back our result set 10 notes and 100 tags, the first and second
response times for Ruby side JSONification  are 187 and 118 milliseconds.
When using PostgreSQL to generate our JSON payload, the response times
are 92 and 12 milliseconds. That is a &lt;strong&gt;2X/10X&lt;/strong&gt; increase. By utilizing
PostgreSQL, we can increase our applications&amp;#39; response times and
throughput.&lt;/p&gt;

&lt;h1&gt;Announce PostgresExt-Serializers&lt;/h1&gt;

&lt;p&gt;To utilize PostgreSQL, we have to generate a fairly complex query
manually. That is, until you include the &lt;a href=&quot;https://github.com/dockyard/postgres_ext-serializers&quot;&gt;PostgresExt-Serializers&lt;/a&gt;
gem into the project. PostgresExt-Serializers (PES) monkey
patches ActiveModel::Serializers (AMS),
and anywhere an ActiveRecord::Relation is serialized by AMS, PES will
take over and push the work to PostgreSQL. I wanted to use the awesome
work of AMS&amp;#39;s DSL for generating JSON schemas without having to duplicate
that work. I am finding some pain points in terms of extracting the
information I need to generate the SQL query from AMS, but right now the
code for PES is very immature, hence the 0.0.1 release.&lt;/p&gt;

&lt;h1&gt;Nitty-Gritty Details About How it All Works: Massive PostgreSQL Queries&lt;/h1&gt;

&lt;p&gt;Let&amp;#39;s say we have an Ember application that we are generating the JSON
request for. The Ember app wants the list of notes, along with the tags
associated with the notes, and we will side load the tags. Side loading
allows you to specify the ids of the tags on the note, and then include
a list of tags, which will be used to instantiate the tags on the note.
The benefit of side loading is that it allows you to save bandwidth by
use tag ids and an array of de-duplicated tags, instead of embedding the
duplicate tags objects under the notes, where you would have to duplicate
the tag objects. We only want notes with &lt;code&gt;id &amp;lt; 40&lt;/code&gt;, which is arbitrary
in this example, but, as we will see, has implications on the query we
need to execute.&lt;/p&gt;

&lt;p&gt;Here is the whole query we need to generate the JSON required, which is
also the example JSON at the beginning of this article:&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
52
53
54
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;-- Note Ids&lt;/span&gt;
WITH notes_ids &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; id
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &amp;lt; &lt;span class=&quot;integer&quot;&gt;40&lt;/span&gt;
),
&lt;span class=&quot;comment&quot;&gt;-- Tag Ids grouped by note id&lt;/span&gt;
tag_ids_by_notes &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, array_agg(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; tag_ids
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;HAVING&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;IN&lt;/span&gt; (
    &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  )
),
&lt;span class=&quot;comment&quot;&gt;-- Tag records&lt;/span&gt;
tags_attributes_filter &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;IN&lt;/span&gt; (
    &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  )
),
&lt;span class=&quot;comment&quot;&gt;-- Tag records as a JSON array&lt;/span&gt;
tags_as_json_array &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; array_to_json(array_agg(row_to_json(tags_attributes_filter)))
&lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; tags, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; match
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags_attributes_filter&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
),
&lt;span class=&quot;comment&quot;&gt;-- Note records&lt;/span&gt;
notes_attributes_filter &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
coalesce(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids_by_notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;::&lt;span class=&quot;predefined-type&quot;&gt;int&lt;/span&gt;[]) &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; tag_ids
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;LEFT&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;OUTER&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids_by_notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids_by_notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &amp;lt; &lt;span class=&quot;integer&quot;&gt;40&lt;/span&gt;
),
&lt;span class=&quot;comment&quot;&gt;-- Note records as a JSON array&lt;/span&gt;
notes_as_json_array &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; array_to_json(array_agg(row_to_json(notes_attributes_filter)))
&lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; notes, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; match
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_attributes_filter&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
),
&lt;span class=&quot;comment&quot;&gt;-- Notes and tags together as one JSON object&lt;/span&gt;
jsons &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
)
&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; row_to_json(jsons) &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;jsons&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s break it down. You&amp;#39;ll notice that I am making use of &lt;a href=&quot;http://www.postgresql.org/docs/9.3/static/queries-with.html&quot;&gt;Common Table
Expressions (CTEs)&lt;/a&gt;. CTEs allow you to use temporary table definitions
in queries instead of embedding the subqueries directly in your query.&lt;/p&gt;

&lt;h2&gt;Gathering our Note Ids&lt;/h2&gt;

&lt;p&gt;The first important step is getting the note ids of our final result
set, which we do with:&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;WITH notes_ids &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; id
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &amp;lt; &lt;span class=&quot;integer&quot;&gt;40&lt;/span&gt;
),
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We are creating a CTE that represents the ids for our notes, we&amp;#39;ll be
using this extensively to generate our tag related records.&lt;/p&gt;

&lt;h2&gt;Getting Tag Ids Grouped by Note Ids&lt;/h2&gt;

&lt;p&gt;From our &lt;code&gt;note_ids&lt;/code&gt;, we can assemble a list of tag ids grouped by notes.
This will be used to create the &lt;code&gt;tag_ids&lt;/code&gt; attribute on the notes later
on.&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;tag_ids_by_notes &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, array_agg(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; tag_ids
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;HAVING&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;IN&lt;/span&gt; (
    &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  )
),
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Our projection is the &lt;code&gt;note_id&lt;/code&gt;, plus an &lt;a href=&quot;http://www.postgresql.org/docs/9.3/static/functions-aggregate.html&quot;&gt;&lt;code&gt;array_agg&lt;/code&gt;&lt;/a&gt; of the id of the
tags in our grouping. &lt;code&gt;array_agg&lt;/code&gt; aggregates the group into an array.
This projection will return the following:&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;note_id | tag_ids
=================
      1 | [1,2]
      2 | [1,3]
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this example, the tags &lt;code&gt;belong_to&lt;/code&gt; a note, so we are retrieving this
data from the &lt;code&gt;tags&lt;/code&gt; table. If this was a many-to-many relation, this
query would execute against the join table (i.e. &lt;code&gt;notes_tags&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We group our tags by the &lt;code&gt;note_id&lt;/code&gt;, and we use the &lt;code&gt;HAVING&lt;/code&gt; clause to
only group tags which have a &lt;code&gt;note_id&lt;/code&gt; contained in the &lt;code&gt;note_ids&lt;/code&gt; CTE
that we created at the beginning.&lt;/p&gt;

&lt;h2&gt;Generating Our Note Records&lt;/h2&gt;

&lt;p&gt;Most of the time, we don&amp;#39;t want to expose all of our record data to
Ember, since whatever we send to the client will be accessible by the
user, whether we intend it to be or not. We filter down the attributes
sent to Ember by limiting the columns in our projection.&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;notes_attributes_filter &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
coalesce(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids_by_notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;::&lt;span class=&quot;predefined-type&quot;&gt;int&lt;/span&gt;[]) &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; tag_ids
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;LEFT&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;OUTER&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids_by_notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tag_ids_by_notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &amp;lt; &lt;span class=&quot;integer&quot;&gt;40&lt;/span&gt;
),
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Also note that in the projection, we are using &lt;a href=&quot;http://www.postgresql.org/docs/9.3/static/functions-conditional.html#FUNCTIONS-COALESCE-NVL-IFNULL&quot;&gt;&lt;code&gt;coalesce&lt;/code&gt;&lt;/a&gt;
to ensure that we return an empty array if a specific note has no &lt;code&gt;tag_ids&lt;/code&gt;.
We are using a &lt;a href=&quot;http://www.postgresql.org/docs/9.3/static/queries-table-expressions.html#QUERIES-JOIN&quot;&gt;&lt;code&gt;LEFT OUTER JOIN&lt;/code&gt;&lt;/a&gt; to combine our previously generated
tag id groupings with our notes. We use an &lt;code&gt;OUTER JOIN&lt;/code&gt; instead of an
&lt;a href=&quot;http://www.postgresql.org/docs/9.3/static/queries-table-expressions.html#QUERIES-JOIN&quot;&gt;&lt;code&gt;INNER JOIN&lt;/code&gt;&lt;/a&gt; so that all our notes are returned, even if no tags are
associated with it. An &lt;code&gt;INNER JOIN&lt;/code&gt; would only return notes that have
tags associated with it. We also use the same &lt;code&gt;WHERE&lt;/code&gt; predicate in this
query as we did in the &lt;code&gt;note_ids&lt;/code&gt; CTE, to ensure our query only returns
the desired records.&lt;/p&gt;

&lt;h2&gt;Turning Our Note Records into a Single JSON Array&lt;/h2&gt;

&lt;p&gt;So now that we have our notes records filtered down, we need to create a
JSON array of these records to use in our final query. At this point, we
will use two of PostgreSQL&amp;#39;s &lt;a href=&quot;http://www.postgresql.org/docs/current/static/functions-json.html&quot;&gt;JSON functions&lt;/a&gt; and the &lt;code&gt;array_agg&lt;/code&gt;
function that we used earlier. &lt;code&gt;row_to_json&lt;/code&gt; takes a PostgreSQL row and
converts it to a JSON object, where the columns of the row converted
into JSON properties.&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;foo | bar
=========
  1 |   2
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Will be converted to&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;     json
================
{ foo: 1, bar: 2 }
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;So at this point, our result set is a series of rows with a single
column of JSON representing the original PostgreSQL row from our
&lt;code&gt;notes_attribute_filter&lt;/code&gt; CTE. We then use &lt;code&gt;array_agg&lt;/code&gt; to turn the
rows of JSON objects into a single row with a single PostgreSQL
Array of JSON objects.&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;     json
================
{ foo: 1, bar: 2 }
{ foo: 1, bar: 2 }
{ foo: 1, bar: 2 }
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;will be converted to&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;                    Array
=======================================================
{{ foo: 1, bar: 2 },{ foo: 1, bar: 2 },{ foo: 1, bar: 2 }}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Lastly, we use &lt;code&gt;array_to_json&lt;/code&gt; to convert the PostgreSQL array of JSON to a JSON array.&lt;/p&gt;

&lt;p&gt;After  combining these pieces, we get the following query:&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;notes_as_json_array &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; array_to_json(array_agg(row_to_json(notes_attributes_filter)))
&lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; notes, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; match
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_attributes_filter&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
),
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;which yields&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;    notes    | match
====================
[{},{},{},{}]|     1
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We are using the &lt;code&gt;notes_attributes_filter&lt;/code&gt; as our source for all the
JSON functions, and adding a column &lt;code&gt;match&lt;/code&gt; with a value of &lt;code&gt;1&lt;/code&gt;, which
we will need later.&lt;/p&gt;

&lt;h2&gt;Aggregating Our Tag Records&lt;/h2&gt;

&lt;p&gt;We apply the attribute filtering and the aggregation techniques to our
&lt;code&gt;tags&lt;/code&gt; table to generate our JSON array of tags. Note that when we
filter the tags attributes, we only include tags that have a &lt;code&gt;note_id&lt;/code&gt;
of a note we are returning.&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;tags_attributes_filter &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;note_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;IN&lt;/span&gt; (
    &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_ids&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  )
),

tags_as_json_array &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; array_to_json(array_agg(row_to_json(tags_attributes_filter)))
&lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; tags, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; match
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags_attributes_filter&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
),
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;which yields&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;    tags     | match
====================
[{},{},{},{}]|     1
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Combining Our Notes and Tags&lt;/h2&gt;

&lt;p&gt;So at this point, we have 2 CTEs that represent our notes and tags. We
need to combine these two tables into a single row, so that we can convert
that row to a JSON object with a &lt;code&gt;notes&lt;/code&gt; and &lt;code&gt;tags&lt;/code&gt; property. This is
the reason we added a &lt;code&gt;match&lt;/code&gt; column onto both CTEs; we join those two
table into our final table, which we then call &lt;code&gt;row_to_json&lt;/code&gt; on to get
our final JSON object, which mirrors the example at the beginning of
this article.&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;jsons &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
  &lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tags_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;notes_as_json_array&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
)
&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; row_to_json(jsons) &lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;jsons&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;So there you have it, you could generate this giant query by hand every
time you need to create an API endpoint, or you could use ActiveModel::Serializers
and utilize the PostgresExt-Seriliazers optimizations to avoid Ruby and
Rails when generating API responses.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building an Ember App with Rails Part 3</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/09/building-an-ember-app-with-rails-part-3" />
    <id>https://dockyard.com/blog/2014/05/09/building-an-ember-app-with-rails-part-3</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="ember" label="Ember.js"/>
    <published>2014-05-09 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;em&gt;This is a four-part series:
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/07/building-an-ember-app-with-rails-part-1.html&quot;&gt;Part 1&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/08/building-an-ember-app-with-rails-part-2.html&quot;&gt;Part 2&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/09/building-an-ember-app-with-rails-part-3.html&quot;&gt;Part 3&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/31/building-an-ember-app-with-rails-part-4.html&quot;&gt;Part 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s implement some navigation in the Boston Ember app.&lt;/p&gt;

&lt;p&gt;Here is a list of sections in the Boston Ember website I&amp;#39;d like to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;About&lt;/li&gt;
&lt;li&gt;Speakers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this part we will work with faked out data. In a future part we will
provide the Rails backend.&lt;/p&gt;

&lt;p&gt;Our first navigation test will be an easy one, create
&lt;code&gt;ember/tests/integration/about-page-test.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; startApp from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bostonember/tests/helpers/start-app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; App;

module(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Integration - About Page&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;beforeEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    App = startApp();
  },
  &lt;span class=&quot;function&quot;&gt;afterEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    Ember.run(App, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should navigate to the About page&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
    click(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&#39;About&#39;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
      assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).text(), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;About&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    });
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After writing this test we can confirm that our test is red in our browser. To make this green we need to add an &lt;code&gt;About&lt;/code&gt; route, 
a link from the landing page to the &lt;code&gt;About&lt;/code&gt; route, and a template for the
&lt;code&gt;About&lt;/code&gt; route.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/router.js&lt;/span&gt;
Router.map(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;about&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/templates/application.hbs&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;h2&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Welcome to Boston Ember&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

{{link-to &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;About&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;about&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;}}

{{outlet}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/templates/about.hbs&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;About&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Boston Ember is the monthly meetup where awesome people get together
to do awesome Ember related things!&lt;span class=&quot;tag&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Your test should now be green. If you navigate to the root path in your
browser you should be able to click through the app. What about getting
back to root? We can add a test to for this navigation as well.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/tests/integration/landing-page-test.js&lt;/span&gt;
test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should allow navigating back to root from another page&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/about&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    click(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Home&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
      assert.notEqual(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).text(), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;About&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    });
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/templates/application.hbs&lt;/span&gt;
{{link-to &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Home&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;}}
{{link-to &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;About&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;about&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Great! A very simple navigation is setup and fully tested. How about something
more complex. Let&amp;#39;s allow our visitors to see the people that have spoken at
Boston Ember. Before we do that we need to add new dependencies to our app for
mocking out remote requests.&lt;/p&gt;

&lt;p&gt;We will be using
&lt;a href=&quot;https://github.com/trek/pretender/tree/0.0.5&quot;&gt;Pretender&lt;/a&gt; by Ember Core
member Trek Glowacki. Pretender is a nice DSL for faking out remote
responses.&lt;/p&gt;

&lt;p&gt;We can use the
&lt;a href=&quot;https://github.com/rwjblue/ember-cli-pretender&quot;&gt;ember-cli-pretender&lt;/a&gt;
Ember CLI Addon to quickly set up Pretender:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;npm install --save-dev ember-cli-pretender
ember install:addon ember-cli-pretender
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You may need to restart your server at this point.&lt;/p&gt;

&lt;p&gt;Tell &lt;code&gt;JSHint&lt;/code&gt; to ignore the &lt;code&gt;Pretender&lt;/code&gt; constant.  Open up
&lt;code&gt;ember/tests/.jshintrc&lt;/code&gt; and add &lt;code&gt;&amp;quot;Pretender&amp;quot;&lt;/code&gt; to the end of the &lt;code&gt;&amp;quot;predef&amp;quot;&lt;/code&gt;
array.&lt;/p&gt;

&lt;p&gt;Finally we need ember-data to make requests namespaced under &lt;code&gt;api&lt;/code&gt; to
our server:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/adapters/application.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; DS from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; DS.ActiveModelAdapter.extend({
  &lt;span class=&quot;key&quot;&gt;namespace&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We should be in a good place to write our tests.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
52
53
54
55
56
57
58
59
&lt;strong&gt;60&lt;/strong&gt;
61
62
63
64
65
66
67
68
69
&lt;strong&gt;70&lt;/strong&gt;
71
72
73
74
75
76
77
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/tests/integration/speakers-page-test.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; startApp from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../helpers/start-app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Pretender from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pretender&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; App, server;

module(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Integration - Speaker Page&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;beforeEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    App = startApp();
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; speakers = [
      {
        &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,
        &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bugs Bunny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
      },
      {
        &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;,
        &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Wile E. Coyote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
      },
      {
        &lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;,
        &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Yosemite Sam&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
      }
    ];

    server = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; Pretender(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/api/speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(request) {
        &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; [&lt;span class=&quot;integer&quot;&gt;200&lt;/span&gt;, {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}, JSON.stringify({&lt;span class=&quot;key&quot;&gt;speakers&lt;/span&gt;: speakers})];
      });

      &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/api/speakers/:id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(request) {
        &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; speaker = speakers.find(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(speaker) {
          &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (speaker.id === parseInt(request.params.id, &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;)) {
            &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; speaker;
          }
        });

        &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; [&lt;span class=&quot;integer&quot;&gt;200&lt;/span&gt;, {&lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;}, JSON.stringify({&lt;span class=&quot;key&quot;&gt;speaker&lt;/span&gt;: speaker})];
      });
    });

  },
  &lt;span class=&quot;function&quot;&gt;afterEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    Ember.run(App, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    server.shutdown();
  }
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should allow navigation to the speakers page from the landing page&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    click(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Speakers&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
      assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).text(), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    });
  });
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should list all speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Bugs Bunny&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Wile E. Coyote&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Yosemite Sam&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).length, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
  });
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should be able to navigate to a speaker page&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    click(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a:contains(&amp;quot;Bugs Bunny&amp;quot;)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
      assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;h4&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).text(), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bugs Bunny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    });
  });
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should be able visit a speaker page&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/speakers/1&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;h4&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).text(), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bugs Bunny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Take a look at the &lt;code&gt;beforeEach&lt;/code&gt; function. There is an array of objects that contains the speaker data, currently only &lt;code&gt;id&lt;/code&gt;s and &lt;code&gt;name&lt;/code&gt;s.
Below that we are setting up the request stubs. Currently this feels
like a lot of boilerplate, and that is because it is. I&amp;#39;m sure
eventually someone will write a nice abstraction to clean this up. This
code simply stubs out the expected server-side calls and returns a JSON
string in the format ember-data expects.&lt;/p&gt;

&lt;p&gt;Our four tests are very simple. The first tests the navigation, the 2nd
tests the speakers are in the list, the 3rd tests that we can navigate
to an individual speaker, and the 4th tests that we can visit the speaker page directly.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s make each pass:&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/router.js&lt;/span&gt;
Router.map(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;about&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.resource(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;// ember/app/templates/application.hbs
{{link-to &#39;About&#39; &#39;about&#39;}}
{{link-to &#39;Speakers&#39; &#39;speakers&#39;}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;// ember/app/templates/speakers.hbs
&amp;lt;h3&amp;gt;Speakers&amp;lt;/h3&amp;gt;

{{outlet}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first test should now be passing.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/router.js&lt;/span&gt;
Router.map(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;about&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.resource(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;speakers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.route(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {&lt;span class=&quot;key&quot;&gt;path&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;:speaker_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;});
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/models/speaker.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; DS from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember-data&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; DS.Model.extend({
  &lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: DS.attr(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// ember/app/routes/speakers/index.js&lt;/span&gt;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; Ember.Route.extend({
  &lt;span class=&quot;function&quot;&gt;model&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.store.find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;speaker&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;// ember/app/templates/speakers/index.hbs
{{#each}}
  {{link-to name &#39;speakers.show&#39; this}}
{{/each}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The 2nd test should now be passing.&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;// ember/app/templates/speakers/show.hbs
&amp;lt;h4&amp;gt;{{name}}&amp;lt;/h4&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The 3rd &amp;amp; 4th tests should now be passing.&lt;/p&gt;

&lt;p&gt;Passing tests are great and all, but let&amp;#39;s actually make the app useable by getting our Rails backend
in the game. &lt;/p&gt;

&lt;p&gt;Let&amp;#39;s generate a model from our Rails app &lt;code&gt;rails g model speaker name:string&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add some seed data:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# rails/db/seeds.rb&lt;/span&gt;
&lt;span class=&quot;constant&quot;&gt;Speaker&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bugs Bunny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;constant&quot;&gt;Speaker&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Wile E. Coyote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;constant&quot;&gt;Speaker&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Yosemite Sam&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Create, migrate and seed &lt;code&gt;rake db:create db:migrate db:seed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add a &lt;code&gt;speakers&lt;/code&gt; resource under an &lt;code&gt;api&lt;/code&gt; namespace:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# rails/config/routes.rb&lt;/span&gt;
namespace &lt;span class=&quot;symbol&quot;&gt;:api&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  resources &lt;span class=&quot;symbol&quot;&gt;:speakers&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now add the controller:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# rails/app/controllers/api/speakers_controller.rb&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Api::SpeakersController&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;index&lt;/span&gt;
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: &lt;span class=&quot;constant&quot;&gt;Speaker&lt;/span&gt;.all
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;show&lt;/span&gt;
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: &lt;span class=&quot;constant&quot;&gt;Speaker&lt;/span&gt;.find(params[&lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;])
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Finally we need to generate a serializer &lt;code&gt;rails g serializer speaker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;name&lt;/code&gt; to the list of attributes to serialize&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;SpeakerSerializer&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveModel&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Serializer&lt;/span&gt;
  attributes &lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Start your Rails server with port &lt;code&gt;3000&lt;/code&gt; and restart your ember server with the command 
&lt;code&gt;ember server --proxy http://localhost:3000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Any remote requests will be proxied to this location.&lt;/p&gt;

&lt;p&gt;Now you can point
your browser to &lt;code&gt;http://localhost:4200&lt;/code&gt;, click on &lt;code&gt;Speakers&lt;/code&gt; and you
should see:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/dcdkJDo.png&quot; alt=&quot;Screen1&quot;&gt;&lt;/p&gt;

&lt;p&gt;That wraps up Part 3. In &lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/31/building-an-ember-app-with-rails-part-4.html&quot;&gt;Part 4&lt;/a&gt; we will get into relationships.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bostonember/website/commit/a21e06a9a29b19d405e50268a6d276b8db758261&quot;&gt;Check out the actual code for this
part&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building an Ember App with Rails Part 2</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/08/building-an-ember-app-with-rails-part-2" />
    <id>https://dockyard.com/blog/2014/05/08/building-an-ember-app-with-rails-part-2</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ember" label="Ember.js"/><category term="ruby" label="Ruby"/>
    <published>2014-05-08 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Writing our first ember test</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;This is a four-part series:
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/07/building-an-ember-app-with-rails-part-1.html&quot;&gt;Part 1&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/08/building-an-ember-app-with-rails-part-2.html&quot;&gt;Part 2&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/09/building-an-ember-app-with-rails-part-3.html&quot;&gt;Part 3&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/31/building-an-ember-app-with-rails-part-4.html&quot;&gt;Part 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;From your project directory root, go to your ember directory and start your server:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;cd ember
ember server
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Open your browser and go to: &lt;code&gt;http://localhost:4200/tests&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see something like the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/bufKV2c.png&quot; alt=&quot;Screen 1&quot;&gt;&lt;/p&gt;

&lt;p&gt;This is a typical &lt;a href=&quot;http://qunitjs.com/&quot;&gt;Qunit&lt;/a&gt; test suite with some
&lt;a href=&quot;http://www.jshint.com/&quot;&gt;JSHint&lt;/a&gt; tests already in our app. What you&amp;#39;ll notice in the lower
right-hand corner is a blank white box. This box is where our
integration tests will execute. This is an IFRAME so we can see our
applications interacted with in real-time (albeit very fast real-time).&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s build out a landing page for our app. We will TDD this entire
application over this multi-part series. Create a new directory and file
&lt;code&gt;ember/tests/integration/landing-page-test.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All of our files will be in
&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts&quot;&gt;ES6
module&lt;/a&gt;
format. If you are unfamiliar with ES6 modules I suggest you go and read
up.&lt;/p&gt;
&lt;div class=&quot;highlight js &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; Ember from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; { module, test } from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;qunit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;
&lt;span class=&quot;reserved&quot;&gt;import&lt;/span&gt; startApp from &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../helpers/start-app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; App;

module(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Integration - Landing Page&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, {
  &lt;span class=&quot;function&quot;&gt;beforeEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    App = startApp();
  },
  &lt;span class=&quot;function&quot;&gt;afterEach&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    Ember.run(App, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }
});

test(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Should welcome me to Boston Ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(assert) {
  visit(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).then(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    assert.equal(find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;h2#title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).text(), &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Welcome to Boston Ember&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Once you save this file go back to your browser. You should not need to reload anything, ember-cli has a live reload feature on file
change. Now you should see your failing test:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/l7y146I.png&quot; alt=&quot;Screen2&quot;&gt;&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s make the test pass:&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;ember/app/templates/application.hbs&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight hbs &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;h2 id=&amp;quot;title&amp;quot;&amp;gt;Welcome to Boston Ember&amp;lt;/h2&amp;gt;
{{outlet}}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Check your test suite and it should be all green.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/242RLGf.png&quot; alt=&quot;Screen3&quot;&gt;&lt;/p&gt;

&lt;p&gt;Congratulations on your first ember test!&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/09/building-an-ember-app-with-rails-part-3.html&quot;&gt;part 3&lt;/a&gt; we&amp;#39;ll build out some pages and write tests to interact with
these pages.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bostonember/website/commit/b17a67b9368acec29c88f4aaa83eceb82a9f143d&quot;&gt;Check out the actual code for this
part&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building an Ember App with Rails Part 1</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/07/building-an-ember-app-with-rails-part-1" />
    <id>https://dockyard.com/blog/2014/05/07/building-an-ember-app-with-rails-part-1</id>
    <category term="ruby" label="Ruby"/><category term="ember" label="Ember.js"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2014-05-07 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>ember-cli &amp; Rails</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;This is a four-part series:
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/07/building-an-ember-app-with-rails-part-1.html&quot;&gt;Part 1&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/08/building-an-ember-app-with-rails-part-2.html&quot;&gt;Part 2&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/09/building-an-ember-app-with-rails-part-3.html&quot;&gt;Part 3&lt;/a&gt;,
&lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/31/building-an-ember-app-with-rails-part-4.html&quot;&gt;Part 4&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This series will take us through building and structuring an application
with an Ember front-end built with
&lt;a href=&quot;https://github.com/stefanpenner/ember-cli&quot;&gt;ember-cli&lt;/a&gt; and a Ruby on
Rails backend. We&amp;#39;ll discuss project structure, testing, and deployment
to Heroku.&lt;/p&gt;

&lt;p&gt;During the course of this series I am going to re-build the
&lt;a href=&quot;http://bostonember.com&quot;&gt;Boston Ember&lt;/a&gt; website. (if it looks terrible
that means I&amp;#39;m not done yet)&lt;/p&gt;

&lt;h2&gt;Getting setup with our tools&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s start by making sure all relevant dev tools are installed on our
machine. I am using the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby 2.1.1&lt;/li&gt;
&lt;li&gt;Rails 4.2.0&lt;/li&gt;
&lt;li&gt;Node 0.12.0&lt;/li&gt;
&lt;li&gt;npm 2.7.0&lt;/li&gt;
&lt;li&gt;Postgres (only necessary because we are deploying to Heroku)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Versions at or above these versions should be OK for following along. Please refer elsewhere on how to install these tools on your development
machine.&lt;/p&gt;

&lt;p&gt;Next I will install ember-cli&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;npm install -g ember-cli
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Confirm that you have &lt;code&gt;ember-cli&lt;/code&gt; installed:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ember --version
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You should see:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;version: 0.2.0
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Or a greater version.&lt;/p&gt;

&lt;h2&gt;Setting up our project&lt;/h2&gt;

&lt;p&gt;For this project we will keep our Rails and our Ember apps in separate
directories with a top-level directory containing the two. We&amp;#39;ll have to
do some project generating and renaming.&lt;/p&gt;

&lt;p&gt;I first create a new top-level directory:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;mkdir bostonember
cd bostonember
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we&amp;#39;re going to generate our Rails project:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;rails new bostonember -B -S -d postgresql
mv bostonember rails
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note how we renamed the directory the Rails project is in to &lt;code&gt;rails&lt;/code&gt;. This
does not affect anything in that directory. If you do not have Postgres
on your machine omit &lt;code&gt;-d postgresql&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now the ember project:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ember new bostonember --skip-git
mv bostonember ember
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now it should be obvious why we moved the Rails project. We should now have
a structure like:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;bostonember
|- ember
|- rails
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s confirm that our ember app runs:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;cd ember
ember server
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In your browser visit &lt;code&gt;http://localhost:4200&lt;/code&gt; and you should see &amp;quot;Welcome to Ember.js&amp;quot;&lt;/p&gt;

&lt;p&gt;At this point you can put everything in your top level directory under
version control:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;git init
git add .
gc -m &amp;quot;Initial commit&amp;quot;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s make some modifications to our Rails app.&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;rm -rf rails/app/assets
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In &lt;code&gt;rails/Gemfile&lt;/code&gt; remove the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;coffee-rails&lt;/li&gt;
&lt;li&gt;jquery-rails&lt;/li&gt;
&lt;li&gt;turbolinks&lt;/li&gt;
&lt;li&gt;jbuilder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now everything related to the Asset Pipeline is completely removed.&lt;/p&gt;

&lt;p&gt;Add the following to the &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;active_model_serializers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;0.9.3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you don&amp;#39;t have Postgres on your machine you can set this for
Production only:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;group &lt;span class=&quot;symbol&quot;&gt;:development&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;sqlite3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

group &lt;span class=&quot;symbol&quot;&gt;:production&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pg&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Run &lt;code&gt;bundle install&lt;/code&gt; in your &lt;code&gt;rails&lt;/code&gt; directory. Let&amp;#39;s commit our
changes:&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;git add -A
gc -m &amp;quot;Removed asset pipeline and added active_model_serializers in Rails&amp;quot;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That wraps up Part 1. In &lt;a href=&quot;http://reefpoints.dockyard.com/2014/05/08/building-an-ember-app-with-rails-part-2.html&quot;&gt;Part 2&lt;/a&gt; will focus on Ember and creating
some functionality in our app.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bostonember/website/commit/cf2d9e18342979b1c187328c4cf29de16599e61d&quot;&gt;Check out the actual code for this
part&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>The other thing DHH mentioned</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/06/the-other-thing-dhh-mentioned" />
    <id>https://dockyard.com/blog/2014/05/06/the-other-thing-dhh-mentioned</id>
    <category term="opinion" label="Opinion"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/>
    <published>2014-05-06 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>The Design Pattern Cargo Culting of the Ruby Community</summary>
    <content type="html">&lt;p&gt;By now &lt;a href=&quot;http://www.confreaks.com/videos/3315-railsconf-keynote&quot;&gt;you&amp;#39;ve probably seen DHH&amp;#39;s Rails Conf 2014 Keynote&lt;/a&gt;. 
Love it or hate it, the one thing you can&amp;#39;t do is deny it got people&amp;#39;s attention. I wasn&amp;#39;t there, and I admit I reacted to Twitter
before actually viewing it. If you only listened on Twitter your
perception of the keynote is most likely that DHH is anti-testing. That
is very far from the truth. Go and watch the video, a lot of what he
talks about resonated with me. I still believe in &amp;quot;testing first&amp;quot; and
&amp;quot;red-green-refactor&amp;quot; but my style is not as dogmatic as some other&amp;#39;s. I
rely on integration tests quite a bit, and I don&amp;#39;t mind hitting the database
during unit tests. Slow tests that actually test how clients
use your app are much better than fast tests that actually test nothing.&lt;/p&gt;

&lt;p&gt;On a side-note, I would be interested to know what DHH thinks about BDD
as opposed to TDD, if he even thinks there is a difference. For me I
feel there is a distinct difference and I would characterize my style of
development as BDD.&lt;/p&gt;

&lt;p&gt;But I don&amp;#39;t want to talk about testing. I want to talk about the other
thing DHH came down on during his keynote: Design Patterns.&lt;/p&gt;

&lt;p&gt;Now before I get raked over the coals let me start by saying that
overall design patterns are great. It was the MVC(ish) and ActiveRecord
patterns that made Rails itself possible. When we speak in patterns it
becomes the lingua franca for programmers. I can jump from language to
language and can, with relative ease, recognize the patterns.&lt;/p&gt;

&lt;p&gt;However, in the Ruby/Rails communities we have gone overboard. Design
Patterns are the new Holy Grail of software development. A few
years ago people were very excited about TDD, as DHH said it was sold to
us as a necessary tool for &amp;quot;professional software development&amp;quot;. Now that
everybody just assumes TDD is happening the thought leaders went in
search of the next intellectually challenging concept to hold everyone
accountable for. This began to spring up maybe 2 years ago, at least
that&amp;#39;s when I started to notice it. Design pattern talks at conferences, books
dedicated to design patterns, podcasts talking about patterns, blog
posts (of which we have written a few), code schools teaching design
patterns - developers ate them up. The Ruby community was hungry for
patterns.&lt;/p&gt;

&lt;p&gt;There feels to me a loss of pragmatism in the ruby community. I think
this is due to there being no major problems to solve in Rails anymore.
Developers are always looking for problems to solve, and in this case
the hive mind has decided to hyper optimize on patterns.&lt;/p&gt;

&lt;p&gt;I get it, they are intellectually stimulating. Implementing a pattern to
&amp;quot;perfection&amp;quot; will give a developer that sense of self-satisfaction. &amp;quot;My
code is clean&amp;quot;. Until the next feature comes in and you have to blow up
what you&amp;#39;ve been perfecting.&lt;/p&gt;

&lt;p&gt;Be pragmatic. Don&amp;#39;t follow the trends just because some guys behind a
microphone say you should.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Preserve scrolling position in Ember Apps</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/05/preserve-scroll-position-in-ember-apps" />
    <id>https://dockyard.com/blog/2014/05/05/preserve-scroll-position-in-ember-apps</id>
    <category term="ember" label="Ember.js"/>
    <published>2014-05-05 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A simple mixin for your views</summary>
    <content type="html">&lt;p&gt;If you have a long list of items on a page and a user follows a link
then goes back to that list, Ember will re-render the list and the user
loses their place. This can be annoying if there is a very long list of
items and the user is expected to be switching back and forth between
the list and the item.&lt;/p&gt;

&lt;p&gt;We can preserve the position by taking advantage of &lt;code&gt;didInsertElement&lt;/code&gt;
on the list&amp;#39;s view.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;jsbin-embed&quot;
href=&quot;http://emberjs.jsbin.com/nevaxipe/2/embed?output&quot;&gt;Ember Starter
Kit&lt;/a&gt;&lt;script src=&quot;http://static.jsbin.com/js/embed.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: there seems to be a bug with the latest stable in Chrome where
the position is never reset if you hit the backbutton. In reality it is
but the position doesn&amp;#39;t render until you scroll. Canary seems OK as do
other browsers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the above example you can scroll down, click on an item, then head
back to the list and be in your original position. This is all done with
the following mixin:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; ScrollableMixin = Ember.Mixin.create({
  &lt;span class=&quot;key&quot;&gt;scrollingTimeout&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;100&lt;/span&gt;,
  &lt;span class=&quot;function&quot;&gt;bindScrolling&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; self = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;,
    &lt;span class=&quot;function&quot;&gt;onScroll&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
      Ember.run.debounce(self, self.runScrolled, self.scrollingTimeout);
    };

    Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(document).on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;touchmove.scrollable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, onScroll);
    Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(window).on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;scroll.scrollable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, onScroll);
  }.on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;didInsertElement&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),

  &lt;span class=&quot;function&quot;&gt;unbindScrolling&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(window).off(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.scrollable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(document).off(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.scrollable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }.on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;willDestroyElement&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),

  &lt;span class=&quot;function&quot;&gt;preservePos&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(window).scrollTop(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.getWithDefault(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller.currentPos&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;));
  }.on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;didInsertElement&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),

  &lt;span class=&quot;function&quot;&gt;runScrolled&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; position = Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(document).height() - Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(window).scrollTop();
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; viewportHeight = document.documentElement.clientHeight;
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller.currentPos&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(window).scrollTop());
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You then mix it into your list&amp;#39;s view:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ThingsView = Ember.View.extend(ScrollableMixin);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Stop using Ember Appkit Rails</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/04/stop-using-ember-appkit-rails" />
    <id>https://dockyard.com/blog/2014/05/04/stop-using-ember-appkit-rails</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ember" label="Ember.js"/><category term="ruby" label="Ruby"/>
    <published>2014-05-04 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Just stop</summary>
    <content type="html">&lt;p&gt;A few months ago I released a gem called &lt;a href=&quot;https://github.com/dockyard/ember-appkit-rails&quot;&gt;Ember Appkit
Rails&lt;/a&gt;. Let me start by
apologizing for its existence. For those that began projects around
eak-rails it started with good intentions and felt right at first but we
have abandoned the gem at DockYard.&lt;/p&gt;

&lt;p&gt;eak-rails was/is a merging of &lt;a href=&quot;https://github.com/stefanpenner/ember-app-kit&quot;&gt;Ember App
Kit&lt;/a&gt; and Rails. It does
some heavy monkey patching to Rails&amp;#39; Asset Pipeline to give as much
project hierarchical power to your Ember code as your Rails code
enjoys.&lt;/p&gt;

&lt;p&gt;We used eak-rails in smaller projects, and intro to Ember courses. In
small doses eak-rails felt right. However, when the surface area of an
application increased eak-rails did not scale well. Having your Ember
and Rails files mixed into the same directories created more problems
than it solved.&lt;/p&gt;

&lt;p&gt;This week I will be focusing on how we are building Ember apps
backed with Rails at DockYard. Part of that will be in-line with what
fellow DockYarder &lt;a href=&quot;https://www.youtube.com/watch?v=ceFNLdswFxs&amp;amp;t=1h8m20s&quot;&gt;Dan McClain presented at Boston Ember last
month&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For eak-rails users, we have not abandoned you. Anybody refusing to
migrate we&amp;#39;ll continue any &lt;strong&gt;critical&lt;/strong&gt; bug fixes but no new features.
We actually sunset the gem about 2 months ago.&lt;/p&gt;

&lt;p&gt;ember-cli is the future.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Guarding with arrays</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/03/guarding-with-arrays" />
    <id>https://dockyard.com/blog/2014/05/03/guarding-with-arrays</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2014-05-03 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A common pattern we use</summary>
    <content type="html">&lt;p&gt;This week I applied a pattern I&amp;#39;ve been using for years to two
separate pull requests from our devs. (I like to review almost all of the
code that DockYard devs write)&lt;/p&gt;

&lt;p&gt;In both cases I was able to help them refactor their code to use an
enumerator as code guards instead of conditional statements. Let&amp;#39;s take a
look at each example:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;users = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.where(&lt;span class=&quot;key&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)

&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; users.any?
  users.each &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |user|
    &lt;span class=&quot;comment&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this first example the &lt;code&gt;each&lt;/code&gt; is avoided if the &lt;code&gt;users&lt;/code&gt;
collection is empty. However, with arrays the enumerator only acts on each
member of the collection so we don&amp;#39;t need to avoid if the collection is
empty. We can refactor the above code into something like this:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.where(&lt;span class=&quot;key&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).each &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |user|
   &lt;span class=&quot;comment&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Much cleaner!&lt;/p&gt;

&lt;p&gt;The next example may not be as straight forward but as we&amp;#39;ll see with
Ruby we can clean this up nicely.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; params[&lt;span class=&quot;symbol&quot;&gt;:ids&lt;/span&gt;]
  params[&lt;span class=&quot;symbol&quot;&gt;:ids&lt;/span&gt;].each &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |id|
    &lt;span class=&quot;comment&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here we have a situation where &lt;code&gt;params[:ids]&lt;/code&gt; could contain a collection
of data. Or it could be &lt;code&gt;nil&lt;/code&gt;. Because of this we cannot just assume we
can always iterate over that value. In Ruby we can create a new &lt;code&gt;Array&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Array([&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;])
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; [1,2,3]&lt;/span&gt;

Array(&lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;)
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; []&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice in the second example that when we pass &lt;code&gt;nil&lt;/code&gt; it creates an
&lt;strong&gt;empty array&lt;/strong&gt;. Knowing this we can refactor our code:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Array(params[&lt;span class=&quot;symbol&quot;&gt;:ids&lt;/span&gt;]).each &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |id|
  &lt;span class=&quot;comment&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you find yourself putting guards around enumerators odds are you can
refactor in a similar manner as I&amp;#39;ve shown above.&lt;/p&gt;

&lt;p&gt;BTW, I&amp;#39;ve been using this pattern for years but I don&amp;#39;t know if there is
an actual name for this. If you do please share!&lt;/p&gt;
</content>
  </entry><entry>
    <title>What is holding up the uniqueness validator?</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/02/what-is-holding-up-uniqueness-validator" />
    <id>https://dockyard.com/blog/2014/05/02/what-is-holding-up-uniqueness-validator</id>
    <category term="ember" label="Ember.js"/>
    <published>2014-05-02 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>One of the more requested features of ember-validations</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/dockyard/ember-validations&quot;&gt;ember-validations&lt;/a&gt; has
nearly all of the &lt;a href=&quot;https://github.com/dockyard/ember-validations#validators&quot;&gt;validator
rules&lt;/a&gt; one needs.
One glarring omission is the &lt;code&gt;Uniqueness&lt;/code&gt; validator.&lt;/p&gt;

&lt;h3&gt;Not as straight forward as one would think&lt;/h3&gt;

&lt;p&gt;Before we even talk about the complication with implementing the remote
validator, we should talk about if &lt;code&gt;uniqueness&lt;/code&gt; should be both a remote 
&lt;strong&gt;and&lt;/strong&gt; local validator.&lt;/p&gt;

&lt;p&gt;Imagine you are working with
&lt;a href=&quot;https://github.com/emberjs/data&quot;&gt;ember-data&lt;/a&gt;, you attempt to create a
new record with an email &lt;code&gt;test@example.com&lt;/code&gt;. If you already have a
record with that value for email in ember-data&amp;#39;s store should
&lt;code&gt;uniqueness&lt;/code&gt; first defer here before we hit remote? This ends up being a
strange thing because what if you have not persisted that first record
yet. Do we only run uniqueness checks against local records that have
been persisted? And how exactly would this fit in if you are mixing your
validations into the controller instead of the model?&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;email&lt;/code&gt; example isn&amp;#39;t working for you, imagine you are adding a
bunch of line items to a parent record. None of these line items have
been persisted yet. And you don&amp;#39;t want to allow your users to add
another until the current one they are working on is &amp;quot;valid&amp;quot;. Validating
uniqueness locally is all of a sudden very valuable. But also very
complex to implement properly.&lt;/p&gt;

&lt;h3&gt;No standard yet&lt;/h3&gt;

&lt;p&gt;If the local validator is too complex of an animal to tackle perhaps the
remote validator implementation will be easier. It is, in part at least.
We can rely on &lt;code&gt;Ember.run.debounce&lt;/code&gt; to ensure the the remote validator
doesn&amp;#39;t fire too frequenly when many changes are happening to the value
of a property. (i.e. entering text into a field)&lt;/p&gt;

&lt;p&gt;But where do we send this request for uniqueness? This is where I am
currently hung up. I really don&amp;#39;t want to implement a backend api
expectation into ember-validations. I was hoping that something like
&lt;a href=&quot;http://jsonapi.org&quot;&gt;json-api&lt;/a&gt; would define this for me then I could rely upon that as a
starting expected endpoint. But I don&amp;#39;t think this is anywhere on their
radar.&lt;/p&gt;

&lt;p&gt;This being said, there is a possible solution. One of my co-workers &lt;a href=&quot;https://twitter.com/linstula&quot;&gt;Lin
Reid&lt;/a&gt; has put together a PR for
introducing remote uniqueness to ember-validations. It is lacking tests
(hint hint, Lin!) but I think &lt;a href=&quot;https://github.com/dockyard/ember-validations/pull/117&quot;&gt;this is moving in the right
direction&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To summarize, uniqueness is not forgotten. It is just a pain in the ass
to do properly. Personally, I would prefer not to implement an API have
people buy into it now and have to change it (or be locked into it) a
few months from now.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Alert messages in Ember Apps</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/05/01/alert-messages-in-ember-apps" />
    <id>https://dockyard.com/blog/2014/05/01/alert-messages-in-ember-apps</id>
    <category term="ember" label="Ember.js"/>
    <published>2014-05-01 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>The wonder of Woof!</summary>
    <content type="html">&lt;p&gt;Something that feels missing from Ember is a way to send, from anywhere
in my app, a general alert message. Something that would pop up in my
app, display for a few seconds and disappear.&lt;/p&gt;

&lt;p&gt;Clearly, this is something that should not be part of Ember itself but it
is a common enough feature that someone should build it.&lt;/p&gt;

&lt;p&gt;I call it &lt;code&gt;Woof&lt;/code&gt;.&lt;/p&gt;

&lt;iframe width=&quot;620&quot; height=&quot;465&quot;
src=&quot;//www.youtube.com/embed/8wfG8ngFvPk&quot; frameborder=&quot;0&quot;
allowfullscreen&gt;&lt;/iframe&gt; 

&lt;p&gt;It currently only exists on &lt;a href=&quot;http://jsbin.com&quot;&gt;jsbin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;jsbin-embed&quot;
href=&quot;http://jsbin.com/luhoquxi/7/embed?output&quot;&gt;WoofWoof! Notifier for
Ember&lt;/a&gt;&lt;script src=&quot;http://static.jsbin.com/js/embed.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;So for the time being you&amp;#39;ll need to copy/paste. We&amp;#39;ll be extracting it
into a plugin soon enough.&lt;/p&gt;

&lt;p&gt;Basically, Woof will inject itself into your routes, controllers, and
components. You will need to embed the Woof component somewhere in your
templates:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;x-woof&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Woof injects a &lt;code&gt;woof&lt;/code&gt; object similar to how &lt;code&gt;ember-data&lt;/code&gt; injects a
&lt;code&gt;store&lt;/code&gt; object. You can push a message onto Woof using some of the
pre-defined types or create your own:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.woof.info(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;This is an info message&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.woof.pushObject({&lt;span class=&quot;key&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;customType&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;message&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Woof! Woof!
Woof!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This code comes with Twitter Bootstrap types setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;danger&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;info&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;success&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;warning&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;x-woof&lt;/code&gt; component will loop through all woofs in the array and
print out a div with the type as the class for specific styling
purposes.&lt;/p&gt;

&lt;p&gt;The code in the JSBin is setup and styled for Twitter Bootstrap.
The event handling is setup for removing the woof when the
css opacity transition completes. Browser support may vary.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Understanding validation graphs</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/04/30/understanding-validation-graphs" />
    <id>https://dockyard.com/blog/2014/04/30/understanding-validation-graphs</id>
    <category term="ember" label="Ember.js"/>
    <published>2014-04-30 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>The power behind ember-validations</summary>
    <content type="html">&lt;p&gt;If you have heard me speak about
&lt;a href=&quot;https://github.com/dockyard/ember-validations&quot;&gt;ember-validations&lt;/a&gt; then
you may have heard me mention the term &lt;strong&gt;validation graph&lt;/strong&gt;. What is
this? Why is it important?&lt;/p&gt;

&lt;p&gt;If you come from a Rails background then you are used to the validations
being stored in an array on the instance of the model. When you validate
your model all of those validations will be run and an errors object is
produced. If you make a change to a property you have to run the
validations again to determine the validity of the model.&lt;/p&gt;

&lt;p&gt;I would refer to the style of
validations described above as &lt;em&gt;lazy validations&lt;/em&gt;. Meaning the
validity of the model may not be truly representative of its
current state. We have to opt-into running the validations again to
determine this. Fortunately in most cases, the validations will run for us
before we save. On the server this all happens within a request/response
cycle so we don&amp;#39;t really care too much about the validations
being lazy because we care about the final result, not the state of the
model at any given point during that cycle.&lt;/p&gt;

&lt;p&gt;ember-validations has &lt;em&gt;eager validations&lt;/em&gt;. This means when the property
that is associated with any number of validations changes those
validations will run again to determine the state of the model. This is
great for client side apps that need to show the current state of the
entire model any time you make a change, say during a user sign up. I
might want to disable the Submit button if there are any failing
validations. If I make a correction I want the error message to go away
once the correction is made. I should not have to wait upon form
submission to see my errors.&lt;/p&gt;

&lt;p&gt;How does ember-validations do this? Let&amp;#39;s say you have the following
validations:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; UsersController =
Ember.ObjectController.extend(Ember.Validations.Mixin, {
  &lt;span class=&quot;key&quot;&gt;validations&lt;/span&gt;: {
    &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: {
      &lt;span class=&quot;key&quot;&gt;presence&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;length&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;
    },
    &lt;span class=&quot;key&quot;&gt;password&lt;/span&gt;: {
      &lt;span class=&quot;key&quot;&gt;confirmation&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There are 3 validations on 2 properties. Each validation is an
instantiated class that can observe the one or more properties. In the
case of the &lt;code&gt;firstName&lt;/code&gt; property the &lt;code&gt;Presence&lt;/code&gt; and &lt;code&gt;Length&lt;/code&gt; validators
are observing it. The &lt;code&gt;Confirmation&lt;/code&gt; validator is actually
observing &lt;code&gt;password&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;passwordConfirmation&lt;/code&gt; for changes. Each
validator has a &lt;code&gt;isValid&lt;/code&gt; flag that is set to &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;
depending upon the result. Each of these validators are pushed onto a
&lt;code&gt;_validators&lt;/code&gt; array and the parent object is observing
&lt;code&gt;_validators.@each.isValid&lt;/code&gt; for any changes. If any of the validators
are &lt;code&gt;false&lt;/code&gt; the parent&amp;#39;s &lt;code&gt;isValid&lt;/code&gt; state is now &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Please take a moment to re-read the above paragraph because it is very
important to have a good handle on this before we move forward. &lt;strong&gt;The
validating object&amp;#39;s &lt;code&gt;isValid&lt;/code&gt; flag is the result of its validator&amp;#39;s
&lt;code&gt;isValid&lt;/code&gt; flags&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because we are in quack-quack duck-typed JavaScript we don&amp;#39;t &lt;strong&gt;have&lt;/strong&gt; to
pass validator instances into the &lt;code&gt;_validators&lt;/code&gt; array. &lt;em&gt;What if we pass
another validatable object?&lt;/em&gt; Now things get interesting.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s say we have a &lt;code&gt;Profile&lt;/code&gt; that belongs to a &lt;code&gt;User&lt;/code&gt;. The &lt;code&gt;Profile&lt;/code&gt;
can have its own set of validations as well as its own &lt;code&gt;isValid&lt;/code&gt; flag.
If the &lt;code&gt;Profile&lt;/code&gt; is mixed into the &lt;code&gt;Users&lt;/code&gt;&amp;#39;s validation graph then the
&lt;code&gt;User&lt;/code&gt; will be invalid when the &lt;code&gt;Profile&lt;/code&gt; is invalid. We can use this
pattern to build an incredibly deep and complex graph where the validation
state bubbles up to the root whenever a property change takes place
anywhere in the graph.&lt;/p&gt;

&lt;p&gt;We can do this simply with:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; UsersController =
Ember.ObjectController.extend(Ember.Validations.Mixin, {
  &lt;span class=&quot;key&quot;&gt;validations&lt;/span&gt;: {
    &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: {
      &lt;span class=&quot;key&quot;&gt;presence&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;,
      &lt;span class=&quot;key&quot;&gt;length&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;
    },
    &lt;span class=&quot;key&quot;&gt;password&lt;/span&gt;: {
      &lt;span class=&quot;key&quot;&gt;confirmation&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    },
    &lt;span class=&quot;key&quot;&gt;profile&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice &lt;code&gt;profile: true&lt;/code&gt; in the graph. As long as &lt;code&gt;profile&lt;/code&gt; is the path to
the object to validate against ember-validations will work its magic.&lt;/p&gt;

&lt;p&gt;However, the above only really works if the validations exist on the
&lt;code&gt;Profile&lt;/code&gt; &lt;strong&gt;model&lt;/strong&gt; and not the controller.&lt;/p&gt;

&lt;p&gt;A visualization of a complex validation graph might look like this. We
can see the &lt;code&gt;isValid&lt;/code&gt; states bubbling up to the original root node:&lt;/p&gt;

&lt;p&gt;&lt;img style=&quot;width: auto&quot; src=&quot;http://i.imgur.com/QP2sYWT.gif&quot;/&gt;&lt;/p&gt;

&lt;p&gt;I welcome suggestions and thoughts on this API as well as the validation graph in general.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The problem with server-rendered errors</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/04/29/the-problem-with-server-rendered-errors" />
    <id>https://dockyard.com/blog/2014/04/29/the-problem-with-server-rendered-errors</id>
    <category term="ember" label="Ember.js"/>
    <published>2014-04-29 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Handling validation errors returned from the server is no easy task</summary>
    <content type="html">&lt;p&gt;The 3rd most popular question with
&lt;a href=&quot;https://github.com/dockyard/ember-validations&quot;&gt;ember-validations&lt;/a&gt; is
how can the library work with server-rendered validation errors, such as
the ones returned with &lt;a href=&quot;https://github.com/emberjs/data&quot;&gt;ember-data&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The short answer for now: it can&amp;#39;t.&lt;/p&gt;

&lt;p&gt;(btw, 2nd most popular question is about &lt;code&gt;uniqueness&lt;/code&gt;/remote validations
and the 1st most popular question is when will I provide a &lt;code&gt;dist/&lt;/code&gt;
directory... I&amp;#39;ll cover the 2nd Q in an upcoming blog post. As far as
&lt;code&gt;dist/&lt;/code&gt; its never going to happen, ever)&lt;/p&gt;

&lt;p&gt;Here is the problem. When you are dealing with a client-side model and a
server-rendered model there won&amp;#39;t always be a 1-to-1 representation of the
model. In those cases you can rely on ember-data&amp;#39;s serializer to
transform the properties on a server-rendered error object to ones that
exist on the client data model. How about properties that don&amp;#39;t exist at
all in any form on the client? You could have a validation error on
something only meant for server-rendered purposes. How do we best handle
this?&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s imagine for a moment that we can properly map all the properties
back to their client-side equivalents. Now what? How do you resolve
these validation errors? How do you know in the UI when the validation
error has been resolved to clear the error message? Are you preventing data
submission until your client model is valid? If the errors are happening
server-side the odds are high that these are not validations that can be
known to be resolved on the client unless you do another data
submission and wait to see how the server responds.&lt;/p&gt;

&lt;p&gt;So to re-cap the two issues are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Potential lack of context on which properties errors can map back to&lt;/li&gt;
&lt;li&gt;Inability to know when server-rendered validation errors are
satisfied on the client&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To start to consider a possible solution I think we need to step back
and consider the ultimate goal of client side validations. In my mind
this is purpose: &lt;em&gt;to help the user submit valid data to the server&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Client side validations are just UI sugar. They are there to guide your
users. ember-validations only has model-layer concerns, which means you
have to provide how the validation errors are displayed on your UI. This
is why I also wrote
&lt;a href=&quot;https://github.com/dockyard/ember-easyForm&quot;&gt;ember-easyForm&lt;/a&gt; which
handles the complexity of what I consider to be best practices of how
validation messages should be displayed and cleared. To fix this problem
would have to tackle it from both sides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How will server-rendered errors be stored in the validation graph?
(ember-validations)&lt;/li&gt;
&lt;li&gt;How will server-rendered errors be displayed and resolved in the client?
(ember-easyForm)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Storing server-rendered errors&lt;/h3&gt;

&lt;p&gt;If you are already using ember-data then your data model is handling
this for you already. IMO you should never mix your validations into
your data model, they should be mixed into your controller:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; UserController =
Ember.ObjectController.extend(Ember.Validations.Mixin, {
  &lt;span class=&quot;key&quot;&gt;validations&lt;/span&gt;: {
    &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: {
      &lt;span class=&quot;key&quot;&gt;presence&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This way the controller has its own &lt;code&gt;errors&lt;/code&gt; object which will not clash
with the &lt;code&gt;errors&lt;/code&gt; object on your data model. One possibility of
referencing the model&amp;#39;s server-rendered errors is to have a &lt;code&gt;base&lt;/code&gt;
validator that is not part of the validation graph but who&amp;#39;s errors can
be used for presentation purposes.&lt;/p&gt;

&lt;h3&gt;Displaying server-rendered errors&lt;/h3&gt;

&lt;p&gt;So how do you properly display these error messages? Do you try to
associate them with a property? What if that property is not represented
by a form input? What if you aren&amp;#39;t even using a form? How do you know
when to clear the errors?&lt;/p&gt;

&lt;p&gt;I believe this is a complex issue. My first pass at handling this in
EasyForm will be to display all of the server-rendered errors in a
single place. An upcoming version of EasyForm will simply group all
errors in &lt;code&gt;base&lt;/code&gt; and display them. These errors will not clear out due
to any corrections made by the client. They will only clear when some
other action clears out those errors, for example when ember-data itself
clears out or changes the content of its &lt;code&gt;errors&lt;/code&gt; object.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;This is far from ideal. This moves us away from the &amp;quot;best practices&amp;quot; for
&lt;a href=&quot;http://alistapart.com/article/inline-validation-in-web-forms&quot;&gt;high conversion forms outlined by Luke
Wroblewski&lt;/a&gt;.
But it is better than not guiding your users. If the server errors for
any given reason we don&amp;#39;t want our users sitting there without any
feedback.&lt;/p&gt;

&lt;p&gt;I am very interested in other approaches and brainstorming on the best
direction for this. Please feel free to comment below.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Don&#39;t override init</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/04/28/dont-override-init" />
    <id>https://dockyard.com/blog/2014/04/28/dont-override-init</id>
    <category term="ember" label="Ember.js"/><category term="best-practices" label="Best Practices"/>
    <published>2014-04-28 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Use events instead</summary>
    <content type="html">&lt;p&gt;Too frequently I see the following problem. Someone creates a new
class and overrides &lt;code&gt;init&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; UsersController = Ember.ArrayController.extend({
  &lt;span class=&quot;function&quot;&gt;init&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;comment&quot;&gt;// some custom stuff&lt;/span&gt;
  }
})

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; UsersController;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;init&lt;/code&gt; is a popular function to override because it is automatically run
after the object is instantiated. It is the only lifecycle hook for
&lt;code&gt;Ember.Object&lt;/code&gt;, subclasses of &lt;code&gt;Ember.Object&lt;/code&gt; add their own hooks to the
lifecycle but the only one that is guaranteed to be there is &lt;code&gt;init&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The problem is with the above example
the controller is broken. I forgot to make a call to &lt;code&gt;this._super()&lt;/code&gt;
which will call the original &lt;code&gt;init&lt;/code&gt; from &lt;code&gt;Ember.ArrayController&lt;/code&gt;. That
&lt;code&gt;init&lt;/code&gt; assigns the proper value to &lt;code&gt;content&lt;/code&gt;. (via &lt;code&gt;ArrayProxy&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Instead of overriding &lt;code&gt;init&lt;/code&gt; I have been writing functions that are
specific to the logic I want to kick off on object instantiation and
have that function trigger &lt;code&gt;on(&amp;#39;init&amp;#39;)&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; UsersController = Ember.ArrayController.extend({
  &lt;span class=&quot;function&quot;&gt;doSomething&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;comment&quot;&gt;// some custom stuff&lt;/span&gt;
  }.on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
})

&lt;span class=&quot;reserved&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;default&lt;/span&gt; UsersController;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now I don&amp;#39;t risk messing with the original behavior of the parent class.&lt;/p&gt;

&lt;p&gt;Calling up the &lt;code&gt;super&lt;/code&gt; chain is a powerful and important feature in
Ember but too often I was forgetting to call it. Now the only time I find
myself overriding &lt;code&gt;init&lt;/code&gt; is if I want to &lt;strong&gt;disrupt&lt;/strong&gt; the default instantiating
behavior of the object.&lt;/p&gt;
</content>
  </entry><entry>
    <title>The first two months at DockYard</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/04/28/first-few-months" />
    <id>https://dockyard.com/blog/2014/04/28/first-few-months</id>
    <category term="user-experience" label="User Experience"/><category term="design-thinking" label="Design Thinking"/><category term="design" label="Design"/>
    <published>2014-04-28 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Maria Matveeva</name></author>
    <summary>Recurring themes, and principles I learned in breaking into user experience design.</summary>
    <content type="html">&lt;h1&gt;The first two months at DockYard.&lt;/h1&gt;

&lt;p&gt;Recurring themes, and principles I learned in breaking into user experience design.&lt;/p&gt;

&lt;h2&gt;Invisible&lt;/h2&gt;

&lt;p&gt;The way I see websites has changed after a month and a half of paying attention to website UI. One thing that stands out: good design can support the message and content in a quiet, almost invisible way. This principle applies in all areas of design, but I am particularly focusing on elegant solutions in web interfaces. It is a pleasure to observe, and sometimes find myself, effective use of subtle visual changes. &lt;/p&gt;

&lt;p&gt;The principle of quiet, effective solutions comes up most often when my work-in-progress is reviewed by the whole team. In most cases, I find that I start a design with many elements in a very âloudâ state, then evaluate the entire layout. Once I can prioritize things on the page, most elements can become more âquietâ.&lt;/p&gt;

&lt;h2&gt;Design for a typical case, not the worst case.&lt;/h2&gt;

&lt;p&gt;Before DockYard, my process relied heavily on finding out what the worst-case scenario could be, and designing for that. For example, I would consider a very long, but still plausible, title for an article, and then design the header to accommodate that comfortably. Iâd always consider extreme cases early on, and design heavily around those. &lt;/p&gt;

&lt;p&gt;At DockYard, I learned to design for the typical use case, and then consider how an extreme case would be accommodated. Looking back, I realize that this approach is less limiting and can result in better graphical solutions.&lt;/p&gt;

&lt;h2&gt;Information density&lt;/h2&gt;

&lt;p&gt;Different use cases call for different densities of information. &lt;/p&gt;

&lt;p&gt;When you are scanning through many search results, it is sometimes appropriate to show a lot of detail at once. Search results are basically many repetitions of one type of item. Users may want to compare what they see according to different criteria, and it is useful to neatly show many details about each result. If Iâve done a good job prioritizing the detailed information, many details do not cause clutter.&lt;/p&gt;

&lt;p&gt;In other cases, it is more important to convey the atmosphere around a brand, or to highlight one or two primary actions. Showing fewer items and fewer details can work better.  In these cases, the density of information may appear low, but each element has more prominence.&lt;/p&gt;

&lt;p&gt;I can make good progress towards solving the layout of a page by deciding whether it is a detailed type of page (like search results) or a page focused on emotional impact, but not details (like some landing pages).&lt;/p&gt;

&lt;h2&gt;Does it look ârealâ?&lt;/h2&gt;

&lt;p&gt;Design is often about deciding what kind of animal a chunk of information will be. Through visual design, we have to clearly answer questions like âhow important is this thing, relative to others?â, âwhat can I do with this?â and even âwhat kind of thing is it?â. When I show a draft in a design review, I can see how the suggested changes âsnapâ to something that looks more real and interactive. I believe that the ability to make things look real quickly comes from experience, and also from paying attention to how user interface elements are crafted in products I use every day.&lt;/p&gt;

&lt;p&gt;Through regular design reviews, close observation of UI design, and occasional experiments, I hope to continue improving my ability to judge my own work. This will allow for more efficient work, more refined design, and more awesomeness in the future.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Artist: Ryo Takemasa</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/04/25/ryo-takemasa" />
    <id>https://dockyard.com/blog/2014/04/25/ryo-takemasa</id>
    <category term="design" label="Design"/><category term="illustration" label="Illustration"/><category term="inspiration" label="Inspiration"/>
    <published>2014-04-25 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Logan Faerber</name></author>
    <summary>Highlighting an inspiring artist</summary>
    <content type="html">&lt;h2&gt;Artist: Ryo Takemasa&lt;/h2&gt;

&lt;p&gt;If youâre not using Pinterest yet to collect various reference material and inspirational artists, may I suggest doing so immediately? I typically like to keep a huge assortment of âmood boardsâ on various topics, ranging from product designs to comic books to grandiose natural landscape photography. It serves as an endless source of reference material, much like collecting magazine clippings and organizing them in various folders. Not only is it great for collecting all of the art you love in one place, itâs also a great platform for discovering new artists. A list of suggestions titled, âother pins like...â is displayed below the piece youâre currently viewing. This often times leads me down an endless tunnel of discovery - one that typically keeps me digging a hole into the wee hours of the morning.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/PCmNbBH.jpg&quot; alt=&quot;âCucumbersâ by Ryo Takemasa&quot;&gt;&lt;/p&gt;

&lt;p&gt;During one of these excavations, I discovered the artist &lt;a href=&quot;http://ryotakemasa.com/&quot;&gt;Ryo Takemasa&lt;/a&gt;, who I at first mistook as &lt;a href=&quot;http://en.wikipedia.org/wiki/Charley_Harper&quot;&gt;Charley Harper&lt;/a&gt;. The piece I saw was a series of stand alone fruits and vegetables, most of them cut in half to expose their cross section, which all shared a beautiful mixture of what appeared to be wood block print and cut paper. Their geometric and pattern infused forms created lovely shapes alongside color shifts that Iâd typically only see in particular vintage illustrations. Accompanying this pin was a link to his site. It turns out heâs a modern Japanese illustrator who works primarily in the print world for a variety of publications.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/ys1BSS4.jpg&quot; alt=&quot;âYellow Pepperâ by Ryo Takemasa&quot;&gt;&lt;/p&gt;

&lt;p&gt;Once I discovered this, I began to see the Japanese line work and &lt;a href=&quot;https://www.google.com/search?q=Japanese+wood+block+print&amp;amp;safe=active&amp;amp;es_sm=91&amp;amp;espv=210&amp;amp;source=lnms&amp;amp;tbm=isch&amp;amp;sa=X&amp;amp;ei=o__0UuZd5anRAdv0gJgP&amp;amp;ved=0CAgQ_AUoAg&amp;amp;biw=2840&amp;amp;bih=1495&amp;amp;dpr=0.9&quot;&gt;wood block printing&lt;/a&gt; aesthetics shine through in his work. The geometric forms and subtle color transparencies were clearly influenced by Japanese culture, but they still retained that vintage American aesthetic at times as well.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/hTb6KCC.jpg&quot; alt=&quot;âOnionâ by Ryo Takemasa&quot;&gt;&lt;/p&gt;

&lt;p&gt;Iâd be curious to learn what amount of influence Charley Harperâs art had on the world and whether it was a huge influence everywhere, such as territories in Japan. Similarly I would also like to know the amount of influence, if any, ancient Japanese wood block printing had on Charley Harper. Was it a conscious decision or had it inadvertently shown through? If there had been a direct influence, that would significantly alter my view of someone who Iâve alway seen as having emerged purely from American Modernist abstraction. Either way, itâs amazing to think that two people, so separated by distance, culture and era could have produced such distinct, yet aesthetically similar artwork. As is the beauty of influence in this world.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Object Self Troll</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/04/17/ember-object-self-troll" />
    <id>https://dockyard.com/blog/2014/04/17/ember-object-self-troll</id>
    <category term="ember" label="Ember.js"/>
    <published>2014-04-17 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Alex Navasardyan</name></author>
    <summary>Ember.Object.create explained</summary>
    <content type="html">&lt;p&gt;Let&amp;#39;s say we have a &lt;code&gt;Month&lt;/code&gt; object. A &lt;code&gt;Month&lt;/code&gt; has &lt;code&gt;weeks&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Month = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;weeks&lt;/span&gt;: Em.A()
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Consider the following code:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; a = Month.create();
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; b = Month.create();

console.log(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;before a&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, a.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; []&lt;/span&gt;
console.log(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;before b&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, b.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; []&lt;/span&gt;

a.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).pushObject(&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;);
a.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).pushObject(&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;);

console.log(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;after a&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, a.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [1, 2], as you expect&lt;/span&gt;
console.log(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;after b&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, b.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [1, 2], and you&#39;re like O_o&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And another one:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Month = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;weeks&lt;/span&gt;: Em.A()
});

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; a = Month.create({ &lt;span class=&quot;key&quot;&gt;weeks&lt;/span&gt;: Em.A([&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;]) });
&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; b = Month.create();

console.log(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, a.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; [1, 2]&lt;/span&gt;
console.log(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, b.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; []&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The results of the first example are quite surprising, if you are not used
to the prototypical inheritance.&lt;/p&gt;

&lt;p&gt;So what&amp;#39;s going on there? Let&amp;#39;s take a look at the &amp;quot;very scary&amp;quot; Ember.js &lt;code&gt;create&lt;/code&gt; &lt;a href=&quot;https://github.com/emberjs/ember.js/blob/master/packages_es6/ember-metal/lib/platform.js#L39-L52&quot;&gt;function&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;function&quot;&gt;create&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(obj, props) {
  K.prototype = obj;
  obj = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; K();
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (props) {
    K.prototype = obj;
    &lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; prop &lt;span class=&quot;keyword&quot;&gt;in&lt;/span&gt; props) {
      K.prototype[prop] = props[prop].value;
    }
    obj = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; K();
  }
  K.prototype = &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;;

  &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; obj;
};
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you don&amp;#39;t pass any properties to create (&lt;code&gt;props&lt;/code&gt;), all instances of
the &lt;code&gt;Object&lt;/code&gt; will share the same prototype. That&amp;#39;s pretty much the gist
of the prototypical inheritance. It means that any changes on one object will
reflect on the others. That explains the behaviour in the first example.&lt;/p&gt;

&lt;p&gt;If you pass the properties (that ones that you specified at &lt;code&gt;extend&lt;/code&gt; time) to &lt;code&gt;create&lt;/code&gt;,
they are going to be replaced on the instance&amp;#39;s prototype.&lt;/p&gt;

&lt;p&gt;There are two ways of changing the default behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;turn &lt;code&gt;weeks&lt;/code&gt; into a &lt;a href=&quot;http://reefpoints.dockyard.com/2013/09/04/computed_properties_in_ember_js.html&quot;&gt;Computed Property&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;set &lt;code&gt;weeks&lt;/code&gt; on &lt;code&gt;init&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using computed property:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Month = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;weeks&lt;/span&gt;: Ember.computed(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; Em.A();
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this case, &lt;code&gt;weeks&lt;/code&gt; is going to return a new &lt;code&gt;Ember.Array&lt;/code&gt; on &lt;code&gt;get&lt;/code&gt;.
The code will run as you expect, &lt;code&gt;weeks&lt;/code&gt; are not going to be shared.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;init&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Month = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;weeks&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,

  &lt;span class=&quot;function&quot;&gt;init&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;._super();
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, Em.A());
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is very clear and nice technique if you&amp;#39;re not familiar with computed properties.
Overriding &lt;code&gt;init&lt;/code&gt; and calling &lt;code&gt;super&lt;/code&gt; allows to run code upon the object&amp;#39;s creation.
You can set the value for &lt;code&gt;weeks&lt;/code&gt; there.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;on(&amp;#39;init&amp;#39;)&lt;/code&gt; but it&amp;#39;s discouraged because a subclass can provide
its own implementation of &lt;code&gt;setWeeks&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; Month = Ember.Object.extend({
  &lt;span class=&quot;function&quot;&gt;setWeeks&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;weeks&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, Em.A());
  }.on(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Vim: On Your Mark...</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/04/10/vim-on-your-mark" />
    <id>https://dockyard.com/blog/2014/04/10/vim-on-your-mark</id>
    <category term="workflow" label="Workflow"/><category term="vim" label="Vim"/>
    <published>2014-04-10 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>An introduction to the mark motion</summary>
    <content type="html">&lt;p&gt;The strength of Vim&amp;#39;s basic &lt;strong&gt;movement&lt;/strong&gt; commands are immediately apparent.
We can jump four words over with &lt;code&gt;4w&lt;/code&gt; or move to the beginning
of a sentence with &lt;code&gt;(&lt;/code&gt;. Once these movements are engrained to muscle memory,
we can move within files with ease. However, there are certain limitations
to these basic movement commands; wouldn&amp;#39;t it be great if we could move
to different and specific spots within multiple files?&lt;/p&gt;

&lt;p&gt;Today, we&amp;#39;re going to briefly cover a poweful motion strategy:
&lt;strong&gt;mark&lt;/strong&gt; motion.&lt;/p&gt;

&lt;h2&gt;What is a Mark?&lt;/h2&gt;

&lt;p&gt;Marks are essentially &lt;em&gt;hidden&lt;/em&gt; positions that, when set, allow us to
jump back to that specific location or line. What we mean by &lt;em&gt;hidden&lt;/em&gt; is that these marks
are not visible by default; marks are simply invisible points within a file.&lt;/p&gt;

&lt;p&gt;The mark motion command starts with hitting &lt;code&gt;m&lt;/code&gt; - &lt;code&gt;m&lt;/code&gt; for mark - and then setting
a &lt;strong&gt;destination marker&lt;/strong&gt; - either a lowercase letter or uppercase letter.
We&amp;#39;ll introduce the differences among the destination markers soon.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s start by covering a simple example of setting a &lt;strong&gt;lowercase mark&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;Example: Moving With A Lowercase Mark&lt;/h4&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# ~/example1.txt

Here is Line 3
Here is Line 4
Here is Line 5

# On Line #3, use `mn` to set a mark on the letter `n` within the word `Line`.
# Move around the file.
# Go back to the previous mark by hitting: `n
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, in &lt;code&gt;Normal&lt;/code&gt; mode, move to Line #3. Place your cursor on the letter &lt;code&gt;n&lt;/code&gt;
within the word &lt;code&gt;Line&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, set a mark by hitting &lt;code&gt;m&lt;/code&gt; and then the lowercase letter
&lt;code&gt;n&lt;/code&gt;. &lt;code&gt;n&lt;/code&gt; is our lowercase &lt;strong&gt;destination marker&lt;/strong&gt;.
Congratulations, we&amp;#39;ve just set a &lt;strong&gt;lowercase mark&lt;/strong&gt;!
We could of used any lowercase character, but by using the letter &lt;code&gt;n&lt;/code&gt;, we&amp;#39;ve
setup a nice mnemonic device.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now move to Line #5. We&amp;#39;re going to move to our mark now.
Hit &lt;code&gt;`n&lt;/code&gt; - &lt;em&gt;backtick&lt;/em&gt; and &lt;code&gt;n&lt;/code&gt;, our previous destination marker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Notice where our cursor is (&lt;em&gt;hint&lt;/em&gt;: it should be located on the letter &lt;code&gt;n&lt;/code&gt;
within the word &lt;code&gt;Line&lt;/code&gt;).
Huzzah, we are now back to our previous position within the file!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go back to Line #5.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now, hit &lt;code&gt;&amp;#39;n&lt;/code&gt; - &lt;em&gt;single quote&lt;/em&gt; and &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We are now at the beginning of Line #3!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Jumps, Marks and a Few Commands&lt;/h2&gt;

&lt;p&gt;We know how to set a mark with &lt;code&gt;m&lt;/code&gt;, but let&amp;#39;s clarify the two types of mark jumps
and the different types of marks.&lt;/p&gt;

&lt;h2&gt;Two Types of Mark Jumps&lt;/h2&gt;

&lt;h3&gt;Backtick&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;`&amp;lt;mark&amp;gt;&lt;/code&gt; - The &lt;em&gt;backtick&lt;/em&gt; places our cursor directly on the mark.&lt;/p&gt;

&lt;h3&gt;Single Quote&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&amp;#39;&amp;lt;mark&amp;gt;&lt;/code&gt; - The &lt;em&gt;single quote&lt;/em&gt; takes us to the first non-blank character of the
mark&amp;#39;s line.&lt;/p&gt;

&lt;h2&gt;Three Types of Marks&lt;/h2&gt;

&lt;h3&gt;Lowercase Marks&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;a - z&lt;/strong&gt; - These marks preserve locations within a &lt;em&gt;single&lt;/em&gt; file. Each individual file
possesses 26 settable lowercase marks. Lowercase marks are valid as long as the file
remains in the buffer list. Furthermore, lowercase marks can be combined with other
operators.  For example, &lt;code&gt;c`n&lt;/code&gt;, will change everything between the cursor to the
mark, &lt;code&gt;n&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Uppercase Marks&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A - Z&lt;/strong&gt; - These marks preserve locations within &lt;em&gt;multiple&lt;/em&gt; files. Also known
as &lt;strong&gt;file marks&lt;/strong&gt;. These marks, which are shared among all files within the buffer list,
can be used to jump from file to file. File marks can only be used in combination with
operators if the mark is in the current file, i.e. when the current file opened contains
the global file mark.&lt;/p&gt;

&lt;h3&gt;Numbered Marks&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;0 - 9&lt;/strong&gt; - Numbered marks cannot be set directly, instead they are created
automagically and used by the &lt;strong&gt;viminfo-file&lt;/strong&gt; (&lt;code&gt;:help viminfo-file&lt;/code&gt;).
Essentially, the numbered marks store the location of your cursor after closing Vim.
For example, mark &lt;code&gt;0&lt;/code&gt; returns the position of the cursor during your last Vim session,
while mark &lt;code&gt;1&lt;/code&gt; returns the next to last Vim session, and so forth.&lt;/p&gt;

&lt;h2&gt;Some Pertinent Commands&lt;/h2&gt;

&lt;h3&gt;Viewing current marks&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;:marks {argument}&lt;/strong&gt; - &lt;strong&gt;:marks&lt;/strong&gt; will show you all current marks, their file location and
destination marker. We can pass in an &lt;em&gt;argument&lt;/em&gt; to view a range of marks between two marks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;:marks aC&lt;/strong&gt; - will return all marks that are between &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;C&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Deleting Marks&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;:delm[arks] {marks}&lt;/strong&gt; - We can use &lt;code&gt;:delm&lt;/code&gt; or &lt;code&gt;:delmarks&lt;/code&gt; and then pass in marks
that we want to delete.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;:delm aAbB&lt;/strong&gt; - will delete marks labeled &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Okay, What&amp;#39;s So Cool About Marks?&lt;/h2&gt;

&lt;p&gt;Marks can speed up our navigation workflow! Here are a few examples:&lt;/p&gt;

&lt;h4&gt;Discussion: Editing One Large File With Lowercase Marks&lt;/h4&gt;

&lt;p&gt;I&amp;#39;ve found &lt;strong&gt;lowercase marks&lt;/strong&gt; extremely useful when editing multiple portions of
a file. Instead of using &lt;code&gt;CTRL+u&lt;/code&gt;, &lt;code&gt;CTRL+d&lt;/code&gt;, &lt;code&gt;H&lt;/code&gt;, or &lt;code&gt;L&lt;/code&gt; to move up and down
the file, you can set local marks at heavily treaded locations at jump back
and forth among them. Moveover, marks give us the ability to jump to an
exact location - &lt;em&gt;backtick&lt;/em&gt; - or to the beginning of the line - &lt;em&gt;single quote&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;Example: Editing Multiple Files With Uppercase (File) Marks&lt;/h4&gt;

&lt;p&gt;When I first started using Vim (and began programming), I had multiple windows
open constantly on the monitor.  Not only does it quickly become cluttered,
remembering which file is which becomes hairy.&lt;/p&gt;

&lt;p&gt;Files marks to the rescue!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Here are three files we are want to work on. Let&amp;#39;s add some &lt;strong&gt;file marks&lt;/strong&gt;.
Just like lowercase marks, the actual uppercase letter we use does not matter
as long as it is unique.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# ~/sheep.rb&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;# On the word `speak`, place a file mark with `mS` - `S` for &amp;quot;sheep&amp;quot;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;speak&lt;/span&gt;
  puts &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Baah! Baah!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# ~/cat.rb&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;# On the word `speak`, place a file mark with `mC` - `C` for &amp;quot;cat&amp;quot;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;speak&lt;/span&gt;
  puts &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Meow! Meow!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# ~/doge.rb&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;# On the word `speak`, place a file mark with `mD` - `D` for &amp;quot;doge&amp;quot;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;speak&lt;/span&gt;
  puts &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Wow! Ahh yes method! Such quality!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;If we are in &lt;code&gt;~/sheep.rb&lt;/code&gt; and want to jump to the &lt;code&gt;speak&lt;/code&gt; method defined
within &lt;code&gt;~/cat.rb&lt;/code&gt;, we can do so with &lt;code&gt;`C&lt;/code&gt;. Now that we&amp;#39;re in &lt;code&gt;~/cat.rb&lt;/code&gt;,
let&amp;#39;s go to the &lt;code&gt;speak&lt;/code&gt; method within &lt;code&gt;~/doge.rb&lt;/code&gt; with &lt;code&gt;`D&lt;/code&gt;.
Pretty sweet, huh?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;&amp;quot;X&amp;quot; Marks the Spot&lt;/h2&gt;

&lt;p&gt;Hope you enjoyed the basics of Vim &lt;strong&gt;marks&lt;/strong&gt;. We&amp;#39;ve only covered the basics here, so if
you&amp;#39;d like to learn more check the docs.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Designing Within The Browser</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/04/04/design-within-the-browser" />
    <id>https://dockyard.com/blog/2014/04/04/design-within-the-browser</id>
    <category term="design-process" label="Design Process"/><category term="design" label="Design"/>
    <published>2014-04-04 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Steven Trevathan</name></author>
    <summary>Make room for accidental progress.</summary>
    <content type="html">&lt;p&gt;I employ a solid range of design tools and although Iâm spending some of my time designing in the browser, the ideal of designing &lt;em&gt;entirely&lt;/em&gt; in that context is often unrealistic and stifling.&lt;/p&gt;

&lt;h2&gt;Save time for discovery&lt;/h2&gt;

&lt;p&gt;Sometimes an accident leads to an interesting and useful discovery. In art and design this is especially true. In a browser, unfortunately, accidents donât pleasantly surprise you in the way &lt;em&gt;âstaticâ&lt;/em&gt; designs may. In development an accident means broken code â plain and simple. You may stumble on a solution, but youâre not going to be surprised by a random glimpse of order and possibility in the muck of your own broken HTML. Itâs broken until itâs fixed.&lt;/p&gt;

&lt;p&gt;Such a quality of the web is necessary, but I donât find it very helpful for discovering new solutions to visual or experience problems. In the early stages you become very focused on minute details when you should be thinking in broad strokes. In later stages you find yourself seeing larger visual problems and with less power to change it. In many ways, I find designing in the browser akin to designing in the dark.&lt;/p&gt;

&lt;p&gt;There are plenty of browser based design tools attempting to free designers of heavy weights such as Photoshop and allow designers to work without learning advanced HTML and CSS. This is a positive direction, but I still havenât seen the problem solved without losing the element of discovery. Instead of happy accidents, you may experience a gross misunderstanding between your intent, the front end code of the tool youâve chosen, and the DOM. Maybe the tools will get better, and Iâm sure they will, but Iâm not optimistic theyâll be architected to facilitate discovery within the next few years.&lt;/p&gt;

&lt;p&gt;For the time being my opinion is that, in terms of process, improvements in web standards and web technology arenât going to change anything save for ensuring work may be completed in shorter order. We create tools (or products) and advance technology in order to &lt;em&gt;increase&lt;/em&gt; efficiency and &lt;em&gt;improve&lt;/em&gt; human capability. The computer added efficiency for designers by - among many, many other things - being faster and more forgiving than pen and ink, but we still use these older technologies today in tandem with computers.&lt;/p&gt;

&lt;h2&gt;The right tool at the right time&lt;/h2&gt;

&lt;p&gt;We can still integrate designing in the browser as a component of the design process. I donât view this as an allâorânothing deal and our process should be malleable enough to better facilitate reaching the goals of each and every project. Imagine, as an extreme example, that you were told to integrate sketching into your design process. You would absolutely not render your designs âpixel-perfectâ in a sketch book. It beats the whole point of the sketch book and the whole experience would be tremendously debilitating. Instead, youâd probably do at least a little bit of preliminary sketching before opening Photoshop, and return when you need to massage another idea out of your head.&lt;/p&gt;

&lt;p&gt;The benefit of designing in the web, or at least getting a product in the browser sooner, is that you can experience it and identify major problems before youâre past the point of no return. This is a pretty well established idea (that I believe in), but just like using the sketchbook we need to identify when itâs appropriate to pop open a text editor and start punching in markup and styles. Iâll kick this off with two cases where I think designing in the browser is appropriate: prototyping unique interactions and defining visual state changes.&lt;/p&gt;

&lt;h3&gt;Prototyping unique interactions&lt;/h3&gt;

&lt;p&gt;We should prototype and test core product interactions when they are unorthodox. Design patterns should be used where possible, but if we are knowingly going against the grain we need to test that experience in the browser and with users (as available) before making it permanent. This is sometimes after the static design has been completed, but in many cases can be done before anything static has been created.&lt;/p&gt;

&lt;h3&gt;Visual state changes&lt;/h3&gt;

&lt;p&gt;When following design patterns there are still standard things to be fleshed out in the browser: hovers, presses, clicks, fades, sliding interactions, and so on. Generally, if you donât know how an interaction will truly feel and it involves a state change: design it in the browser. At DockYard, we often propose a solution first in Photoshop and then weigh our options again in the browser. &lt;/p&gt;

&lt;h2&gt;An example&lt;/h2&gt;

&lt;p&gt;We completed a project last year with the ambition of the design stage being completely browser based, skipping the use of Photoshop altogether. The benefits of having a usable front end in place of static mockups are great: you can use your app as it is being designed and get a sense of the failure points before they become too ingrained in the experience. User testing can begin earlier. This is awesome. From the outside, designing solely in the browser seemed perfect.&lt;/p&gt;

&lt;p&gt;You guessed it: I was wrong. It wasn&amp;#39;t right for us then, nor for that project. We were less focused on the userâs experience and more focused on the organization and creation of markup, styles, and script. We began (and ended) by worrying about and writing lines of HTML, CSS, and JavaScript. We were worried about front end patterns, but the design patterns we were aiming to support werenât fully identified yet. We introduced somewhat of a chicken and the egg problem, making our thinking more difficult and more sporadic than it should have been.&lt;/p&gt;

&lt;p&gt;For us this meant spending hours and hours tweaking markup, all in the name of being able to feel and test the product as it was created. In some cases, for sure, this can be worth it. In our case we even had plenty of existing design assets to base our web interface off of, but that project had called for too many largely different iterations (and mixed opinions) of the same few designs.&lt;/p&gt;

&lt;p&gt;Designing in the browser does not mean your project will turn out poorly. Ultimately, and fortunately, that project turned out well in the end, but we did spend a lot more time getting a complete idea of what we were actually designing and building. Our clients got to use the product before they bought into the concept, which was great for them. For us, however, it was as if we started designing a house by laying the concrete foundation before knowing what we were building.&lt;/p&gt;

&lt;h2&gt;Weigh your options&lt;/h2&gt;

&lt;p&gt;A successful product depends on its content, design, engineering, market fit, team, tools, and infinitely more. When consulting, those elements are wildly varied from client to client, including the toolset. So we must be mindful of what is necessary, be malleable in our processes, and most important of all: make room for discovery.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Magic behind ES6 Generators</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/03/30/magic_behind_es6_generators" />
    <id>https://dockyard.com/blog/2014/03/30/magic_behind_es6_generators</id>
    <category term="es6" label="ES6"/><category term="javascript" label="JavaScript"/>
    <published>2014-03-30 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Alex Navasardyan</name></author>
    <summary>Overview of ES6 generators</summary>
    <content type="html">&lt;h2&gt;Overview&lt;/h2&gt;

&lt;p&gt;The next version of JavaScript (ES6 or ES.next) is going to have a lot of
great features built in that are going to make developer&amp;#39;s life much easier.
&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=strawman:promises&quot;&gt;Promises&lt;/a&gt;,
&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:modules&quot;&gt;Modules&lt;/a&gt;,
&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:weak_maps&quot;&gt;WeakMaps&lt;/a&gt;,
&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:generators&quot;&gt;Generators&lt;/a&gt; to name a few. In this
post I want to talk about generators.&lt;/p&gt;

&lt;p&gt;Generators are objects that encapsulate suspended execution context. What the heck does it mean?
In other words, generators allow you to pause execution of your code and return a value.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s say you need to write a &lt;code&gt;cubic&lt;/code&gt; function (for any given number, calculate a cubic number)
and then print it out.&lt;/p&gt;

&lt;p&gt;Code without generators for 10 numbers:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;out&lt;/span&gt;(n) {
  console.log(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Cubic number:&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, n);
}

&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; *cube(n) {
  n = n * &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;;
  out(n);
}

&lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;; i++) {
  cube(i);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Code with ES6 generators for 10 numbers:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; *cube(n) {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;, j = n;
  &lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; (i &amp;lt; n) {
    i++;
    j = j * &lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;;
    yield j;
  }
}

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; c = cube(&lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;);
&lt;span class=&quot;keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;; i++) {
  console.log(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Cubic number:&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, c.next().value);
}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Can you spot the difference? Generator represents a sequence of numbers and every time you call
&lt;code&gt;next()&lt;/code&gt; it gives you the next number in the sequence (it actually gives you an object back
with two properties: &lt;code&gt;value&lt;/code&gt; and &lt;code&gt;done&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;c.next(); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; { value: 3, done: false }&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Once the limit is reached, generator will return:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;c.next(); &lt;span class=&quot;comment&quot;&gt;// =&amp;gt; { value: undefined, done: true }&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Pretty cool, eh?&lt;/p&gt;

&lt;p&gt;Note, that generators look &lt;em&gt;just&lt;/em&gt; like functions, but with &lt;code&gt;*&lt;/code&gt;s:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;// regular function&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;cube&lt;/span&gt;()  {}

&lt;span class=&quot;comment&quot;&gt;// es6 generator&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt; *cube() {}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you&amp;#39;re a Python developer, generators and &lt;code&gt;yield&lt;/code&gt; are not new to you. But it&amp;#39;s a big step forward
for JavaScript.&lt;/p&gt;

&lt;h2&gt;For-Of&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;for of&lt;/code&gt; loop is a new iteration construct in ES6 which supports generators. This is really for
performance purposes. Instead of returning a full array, you can just return a generator which
lazily gives values back on each iteration. That decreases memory allocation and you can express
infinite data structures (since no array allocation is needed).&lt;/p&gt;

&lt;p&gt;A really interesting use case for generators is async operations:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;spawn(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; users = yield db.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; posts = yield db.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;posts&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;spawn&lt;/code&gt; is a function in &lt;a href=&quot;http://nodejs.org&quot;&gt;node.js&lt;/a&gt; that allows you to create child processes.
You can read about it &lt;a href=&quot;http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;spawn&lt;/code&gt; hands control over the function to the scheduler, which knows that the function will &lt;code&gt;yield&lt;/code&gt;
promises and will send the values back as soon as the promises are going to be resolved (fulfilled).&lt;/p&gt;

&lt;p&gt;This is really powerful.&lt;/p&gt;

&lt;h2&gt;Availability&lt;/h2&gt;

&lt;p&gt;If you really want to use this feature, you&amp;#39;re going to have to use transpilers, such as &lt;a href=&quot;https://github.com/google/traceur-compiler&quot;&gt;Traceur&lt;/a&gt;
or &lt;a href=&quot;https://github.com/facebook/regenerator&quot;&gt;Regenerator&lt;/a&gt;. The reason for that is two new language keywords
introduced by ES6 generators: &lt;code&gt;yield&lt;/code&gt; and &lt;code&gt;function *&lt;/code&gt;. There&amp;#39;s a really good blog post about &lt;a href=&quot;http://gu.illau.me/posts/polyfilling-generators/&quot;&gt;polyfilling generators&lt;/a&gt;
that goes in depth about how transpilers deal with the new syntax.&lt;/p&gt;

&lt;p&gt;Native implementations of generators are available in Firefox and Chrome Canary
(you will need to enable &lt;a href=&quot;chrome://flags/#enable-javascript-harmony&quot;&gt;harmony experimental flag&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I encourage you to play around with the generators and get familiar with the syntax because in couple of
years from now, we all will be writing code using generators (hopefully).&lt;/p&gt;

&lt;p&gt;P.S.&lt;/p&gt;

&lt;p&gt;Great article about &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.7#Generators&quot;&gt;ES6 generators&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Conf picks up where the Rails community left off</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/03/17/emberconf-picks-ups-where-the-rails-community-left-off" />
    <id>https://dockyard.com/blog/2014/03/17/emberconf-picks-ups-where-the-rails-community-left-off</id>
    <category term="ember" label="Ember.js"/><category term="opinion" label="Opinion"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2014-03-17 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A summary of the first Ember Conference</summary>
    <content type="html">&lt;p&gt;I&amp;#39;m writing this on my flight from Portland back to Boston. On this
plane I count at least 12 other attendees of the first &lt;a href=&quot;http://emberconf.com&quot;&gt;Ember Conference&lt;/a&gt;.
A lot has been said about Ember in the past year but if this conference
was any indicator big things are happening and even bigger things are
going to happen.&lt;/p&gt;

&lt;p&gt;For me, the biggest take away from any conference is the people and
this conference was no exception. In fact, Ember Conf is now my gold
standard for a technology event. The only possible comparison I have is
how early Rails Confs felt. There is an energy and a scary amount of
creativity happening in the Ember community right now. Much like the
community felt around Rails back in 2006 - 2009 there is the
understanding that those doing Ember now are going to be shaping the
future of the web. Whether that is setting the bar higher for how users
will want to consume web applications in the future or being a large
influence on what the future of the web standards themselves will be, Ember
is the only web technology today that is positioned in the same place
that I feel Rails was years ago. We are the rebels. We are the
counter-culture. Ember is the future.&lt;/p&gt;

&lt;p&gt;But, we&amp;#39;re learning from the mistakes of the past. Where the Rails
community was the counter-culture of its time it suffered from a male
(and very juvenile) dominated culture. This culture was the result of
the &amp;quot;RockStar&amp;quot; mentality set forth by its leader(s). Ember, in contrast,
began its very first conference with Yehuda Katz and Tom Dale addressing
the entire crowd with their desire for Ember to be an open and diverse
community.&lt;/p&gt;

&lt;p&gt;The conference was very well organized, big shoutout to Leah Silber at Tilde. She
put on a great conference, I&amp;#39;m proud that my company had the opportunity
to help make it happen.&lt;/p&gt;

&lt;p&gt;From a technology perspective &lt;strong&gt;huge&lt;/strong&gt; things are on the horizon for
Ember. If you have been on the cusp of getting involved you will be
kicking yourself later for not doing so now. If you are already building
in Ember nearly all of the pain-points that have existed will be
addressed in the next 6 months. Testing as a first class citizen,
fastest template rendering of any JavaScript framework/tool out there,
animation support, query params, a standardized project structure and
build tool, and there was even talk of how we&amp;#39;re going to package and
distribute dependencies. Ember Conf was a continuous roll of one great
talk after another loaded with the best tech on the web. I&amp;#39;ve already
really enjoyed writing Ember apps for the past year, the next year will
be amazing.&lt;/p&gt;

&lt;p&gt;I realize at this point the article smacks of cheerleading optimism. How
can it be this good? The real secret weapon of any open source software
is its community. After this week I can tell you that I have not felt
this way about a community since the early days of Rails. There is
something very special happening here. It isn&amp;#39;t just me. &lt;a href=&quot;https://twitter.com/search?q=%23emberconf&amp;amp;src=tyah&quot;&gt;Go search
Twitter for &lt;code&gt;#EmberConf&lt;/code&gt; and see for
yourself&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;People are crying, having
spiritual awakenings and overall life-affirming moments at &lt;a
href=&quot;https://twitter.com/search?q=%23emberconf&amp;amp;src=hash&quot;&gt;#emberconf&lt;/a&gt;
â¦ Think I want whateverâs in their punch&lt;/p&gt;&amp;mdash; Rob Conery
(@robconery) &lt;a
href=&quot;https://twitter.com/robconery/statuses/449041727240695808&quot;&gt;March
27, 2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;ITâS HAPPENING!! HTMLbars
eliminates &amp;lt;script&amp;gt; tags, {{bindAttr}}, and gives Ember the
fastest bound templates on the planet. &lt;a
href=&quot;https://twitter.com/search?q=%23emberconf&amp;amp;src=hash&quot;&gt;#emberconf&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Tom Dale (@tomdale) &lt;a
href=&quot;https://twitter.com/tomdale/statuses/448621833953083392&quot;&gt;March 26,
2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;This scene with &lt;a
href=&quot;https://twitter.com/tomdale&quot;&gt;@tomdale&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/tehviking&quot;&gt;@tehviking&lt;/a&gt; and &lt;a
href=&quot;https://twitter.com/fivetanley&quot;&gt;@fivetanley&lt;/a&gt; sums up &lt;a
href=&quot;https://twitter.com/search?q=%23emberconf&amp;amp;src=hash&quot;&gt;#emberconf&lt;/a&gt;
- so much love â¤ï¸â¤ï¸â¤ï¸ &lt;a
  href=&quot;http://t.co/AEUEeiq97i&quot;&gt;pic.twitter.com/AEUEeiq97i&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Dan Gebhardt (@dgeb) &lt;a
href=&quot;https://twitter.com/dgeb/statuses/449088566962814976&quot;&gt;March 27,
2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;Ember makes you a badass
web developer. The productivity gains are unparalleled. Page flow is
first class. &lt;a
href=&quot;https://twitter.com/search?q=%23emberconf&amp;amp;src=hash&quot;&gt;#emberconf&lt;/a&gt;
&lt;a
href=&quot;http://t.co/DlKqmmdVEU&quot;&gt;pic.twitter.com/DlKqmmdVEU&lt;/a&gt;&lt;/p&gt;&amp;mdash;
John K. Paul (@johnkpaul) &lt;a
href=&quot;https://twitter.com/johnkpaul/statuses/448510256097001472&quot;&gt;March
25, 2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;Notes on the morning &lt;a
href=&quot;https://twitter.com/search?q=%23emberconf&amp;amp;src=hash&quot;&gt;#emberconf&lt;/a&gt;
keynote by &lt;a href=&quot;https://twitter.com/wycats&quot;&gt;@wycats&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/tomdale&quot;&gt;@tomdale&lt;/a&gt; &lt;a
href=&quot;http://t.co/rYKEruaxRe&quot;&gt;pic.twitter.com/rYKEruaxRe&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Michael Chan (@chantastic) &lt;a
href=&quot;https://twitter.com/chantastic/statuses/448517744900976641&quot;&gt;March
25, 2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;hug &lt;a
href=&quot;https://twitter.com/tomdale&quot;&gt;@tomdale&lt;/a&gt; achievement unlocked &lt;a
href=&quot;https://twitter.com/search?q=%23emberconf&amp;amp;src=hash&quot;&gt;#emberconf&lt;/a&gt;
&lt;a
href=&quot;http://t.co/nLOBPGJwKL&quot;&gt;pic.twitter.com/nLOBPGJwKL&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Ben Rosas (@ballPtPenguin) &lt;a
href=&quot;https://twitter.com/ballPtPenguin/statuses/449000521211203586&quot;&gt;March
27, 2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;&lt;a
href=&quot;https://twitter.com/ebryn&quot;&gt;@ebryn&lt;/a&gt; &lt;a
href=&quot;https://twitter.com/EmberConf&quot;&gt;@EmberConf&lt;/a&gt; Such a wonderful
experience. One of the best conferences I&amp;#39;ve ever attended, it was
like one big family finally united.&lt;/p&gt;&amp;mdash; Kasper Tidemann
(@KasperTidemann) &lt;a
href=&quot;https://twitter.com/KasperTidemann/statuses/449044965855723520&quot;&gt;March
27, 2014&lt;/a&gt;&lt;/blockquote&gt;

&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot;
charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
</content>
  </entry><entry>
    <title>A Simple Ember Data Route</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/03/03/a-simple-ember-data-route" />
    <id>https://dockyard.com/blog/2014/03/03/a-simple-ember-data-route</id>
    <category term="ember" label="Ember.js"/>
    <published>2014-03-03 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A basic pattern for routes with Ember Data content</summary>
    <content type="html">&lt;p&gt;When working with an Ember Data model it is easy to forget to properly
handle the teardown of that model. For example, if you are creating a
new model and the user hits the backbutton that model is still in the
local &lt;code&gt;store&lt;/code&gt;. Or if a user edits a model and decides to click the
&lt;code&gt;Cancel&lt;/code&gt; button or clicks a link that transitions out of this route
without saving the model. A basic approach can be as simple as:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Ember.DSModelRoute = Ember.Route.extend({
  &lt;span class=&quot;function&quot;&gt;deactivate&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; model = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller.model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
    model.rollback();
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (model.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isNew&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)) {
      model.deleteRecord();
    }
  },
  &lt;span class=&quot;key&quot;&gt;actions&lt;/span&gt;: {
    &lt;span class=&quot;function&quot;&gt;willTransition&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(transition) {
      &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; model = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller.model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
      &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (model.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isDirty&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &amp;amp;&amp;amp; !confirm(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;You have unsaved changes. They will be lost if you continue!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)) {
        transition.abort();
      }
    }
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Routes inherited from &lt;code&gt;Ember.DSModelRoute&lt;/code&gt; will always clean up after themselves. If the user has unsaved changes and attempts to leave the current route 
the app will guard against the transition and allow the user to confirm with a notice that changes will be lost.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Using Database Templates in Rails</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/03/03/using-database-templates" />
    <id>https://dockyard.com/blog/2014/03/03/using-database-templates</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="postgresql" label="PostgreSQL"/>
    <published>2014-03-03 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Romina Vargas</name></author>
    <summary>Discover a helpful Postgres config option</summary>
    <content type="html">&lt;p&gt;Using Postgres as your application&amp;#39;s database? If so, there is a handy
configuration option that you may not be aware about. The &lt;code&gt;pg&lt;/code&gt; gem provides a &lt;code&gt;template&lt;/code&gt; option that
allows for copying already existing data into an application as
long as you have matching schema. &lt;/p&gt;

&lt;p&gt;To add this functionality, simply add the &lt;code&gt;template&lt;/code&gt; option inside &lt;code&gt;config/database.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight yaml &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;key&quot;&gt;development&lt;/span&gt;:
  &lt;span class=&quot;key&quot;&gt;adapter&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;postgresql&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;key&quot;&gt;encoding&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;unicode&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;key&quot;&gt;database&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;myapp_development&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;key&quot;&gt;template&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;my_template&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s go through a quick example. Suppose we have an existing database, &lt;code&gt;food&lt;/code&gt;, and it contains an abundant amount of data with the
following schema:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;foods: name (string), category_id (integer)
categories: category (string)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To use the &lt;code&gt;food&lt;/code&gt; database for our application, we are going to
create a template by specifying our database with the following command: &lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;createdb -T food my_food_template
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We must now set up our Rails application and make sure that our schema matches
that of our new template. Our Rails models will mimick &lt;code&gt;food&lt;/code&gt;. Having done
that, we can now modify our &lt;code&gt;config/database.yml&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight yaml &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;key&quot;&gt;database&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;myapp_development&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;key&quot;&gt;template&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;my_food_template&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Run migrations and voilÃ ! Our database has been populated and is ready to be used.&lt;/p&gt;
&lt;div class=&quot;highlight bash &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;gt; psql myapp_development

&amp;gt; select * from foods;
  id |  name  | category_id
  --------------------------
  1   apple       1
  2   banana      1
  3   spinach     2
  4   ice cream   3

&amp;gt; select * from categories;
  id |  category
  --------------
  1   fruit
  2   vegetable
  3   other
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;</content>
  </entry><entry>
    <title>Native App Developers: We Can Help You</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/02/07/native-app-developers-we-can-help-you" />
    <id>https://dockyard.com/blog/2014/02/07/native-app-developers-we-can-help-you</id>
    <category term="business" label="Business"/><category term="business-development" label="Business Development"/><category term="mobile" label="Mobile"/><category term="services" label="Services"/>
    <published>2014-02-07 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Dan McClain</name></author>
    <summary>Have an existing application? We can help you out!</summary>
    <content type="html">&lt;p&gt;If you have an existing app, and are looking for a server component,
whether it be adding a syncing service to your app, building out a web
version to extend your user experience, or need a site to showcase your
app, we have both the design and development resources to make that
happen.&lt;/p&gt;

&lt;p&gt;You might have realized that iCloud doesn&amp;#39;t fit your needs, or you want
a web application that interacts with your app. We can build your API to
fit your exact needs, so you don&amp;#39;t need to fight iCloud to fit your
needs. You may be looking to build out a new RSS service that needs to
parse and cache RSS feeds. We have the experience and resources that
will help you bring a server heavy component to your app.&lt;/p&gt;

&lt;p&gt;You may have users looking to use your application when they aren&amp;#39;t on
their phone. We can design and build a rich web application that brings your
app to the browser without losing the spirit of your app. You might need
a marketing site with video demos and screenshots of your app. We can
design and build a site that really shows off your application.&lt;/p&gt;

&lt;p&gt;If any of these sound like you, you should &lt;a href=&quot;https://dockyard.com/hire-us&quot;&gt;get in touch with
us&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Announcing PostgresExt-PostGIS</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/02/07/announcing-postgres_ext-postgis" />
    <id>https://dockyard.com/blog/2014/02/07/announcing-postgres_ext-postgis</id>
    <category term="postgresql" label="PostgreSQL"/><category term="postgis" label="Postgis"/><category term="postgres_ext" label="Postgres_ext"/><category term="postgres_ext-postgis" label="Postgres_ext-postgis"/><category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2014-02-07 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>PostgresExt-PostGIS adds PostGIS support to ActiveRecord</summary>
    <content type="html">&lt;p&gt;Today I released the first version of
&lt;a href=&quot;https://github.com/dockyard/postgres_ext-postgis&quot;&gt;postgres_ext-postgis&lt;/a&gt;, which
extends ActiveRecord to support PostGIS data types and some querying.
This is definitely a beta release, but ready to the point where people
can play around with it.&lt;/p&gt;

&lt;h2&gt;Migrations&lt;/h2&gt;

&lt;p&gt;With postgres_ext-postgis, you can easily add geometry columns:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:districts&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.geometry &lt;span class=&quot;symbol&quot;&gt;:district_boundries&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you&amp;#39;d like to include your projection or geometry type, just include
them as options to your column:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:districts&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.geometry &lt;span class=&quot;symbol&quot;&gt;:district_boundries&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;spatial_type&lt;/span&gt;: &lt;span class=&quot;symbol&quot;&gt;:multipolygon&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;srid&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;4326&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Type Casting&lt;/h2&gt;

&lt;p&gt;Your geometry columns will be typecasted into
&lt;a href=&quot;http://dazuma.github.io/rgeo/&quot;&gt;RGeo&lt;/a&gt; objects. You can set your
attributes with RGeo objects or EWKT/EWKB strings. EWKT/EWKB strings
will be converted to RGeo objects:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;user.location = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;SRID=4623;POINT(1 1)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Querying&lt;/h2&gt;

&lt;p&gt;For now, the only added querying method for ActiveRecord is &lt;code&gt;contains&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;District&lt;/span&gt;.where.contains(&lt;span class=&quot;key&quot;&gt;district_boundries&lt;/span&gt;: user.location)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above query will utilize PostGIS&amp;#39;s &lt;code&gt;ST_CONTAINS&lt;/code&gt; to see if the
&lt;code&gt;district_boundries&lt;/code&gt; column contains the &lt;code&gt;user.location&lt;/code&gt;. I plan to add
a convience method to convert EWKT strings to RGeo object, something
like &lt;code&gt;PostgreExt.geom(&amp;#39;SRID=4623;POINT(1 1)&amp;#39;)&lt;/code&gt;, to make generating
queries from, say, a mobile user&amp;#39;s current location a bit easier.&lt;/p&gt;

&lt;p&gt;As I get feedback and use postgres_ext-postgis, more features will get
added. Stay tuned!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Ember Conf: Ember for Rails Devs</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/02/04/ember-conf-ember-for-rails-devs" />
    <id>https://dockyard.com/blog/2014/02/04/ember-conf-ember-for-rails-devs</id>
    <category term="ember" label="Ember.js"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/><category term="announcement" label="Announcement"/>
    <published>2014-02-04 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Join our one day training session prior to Ember Conf in Portland, Oregon</summary>
    <content type="html">&lt;p&gt;We invite you to learn from DockYard for a day before &lt;a href=&quot;http://emberconf.com&quot;&gt;Ember Conf&lt;/a&gt; in Portland, Oregon. We will be offering a one day training session for Ruby on Rails developers interested in
learning how to build Ember Applications. Over the course of the day we
will teach you the following:&lt;/p&gt;

&lt;h4&gt;Introduction to Higher Level JavaScript Concepts&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;ES6 Modules&lt;/li&gt;
&lt;li&gt;Promises&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Introduction to Ember Concepts&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Client side MVC&lt;/li&gt;
&lt;li&gt;Ember.Object&lt;/li&gt;
&lt;li&gt;All the stuff under the hood of Router, Routes, Models, Controllers,
Components, Templates, and the Runloop&lt;/li&gt;
&lt;li&gt;Ember Data&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Introduction to Ember Appkit Rails&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;How to build a new Ember project with Rails&lt;/li&gt;
&lt;li&gt;Generators&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together we wil build two applications before the day is over. The first
will be a simple CRUD &amp;quot;blog&amp;quot; style application. Time permitting the second will be 
a more advanced desktop-quality style applicaiton.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://emberconf.com/&quot;&gt;Seats are limited, be sure to get your ticket before they sell
out!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;About The Instructors&lt;/h2&gt;

&lt;h4&gt;Brian Cardarella&lt;/h4&gt;

&lt;p&gt;Brian is the CEO of DockYard and has been developing in Ember since late
2012. He was a &lt;a href=&quot;https://www.youtube.com/watch?v=wmQovdFoMm0&quot;&gt;speaker at the &amp;quot;first&amp;quot; Ember conference, Ember Camp, in
      2013&lt;/a&gt;.
      Brian is the author of some popular Ember libraries such as
&lt;a href=&quot;https://github.com/dockyard/ember-validations&quot;&gt;ember-validations&lt;/a&gt; and &lt;a href=&quot;https://github.com/dockyard/ember-easyForm&quot;&gt;ember-easyForm&lt;/a&gt;. Recently he has been focusing most
of his open source time on building &lt;a href=&quot;https://github.com/dockyard/ember-appkit-rails&quot;&gt;Ember Appkit
Rails&lt;/a&gt;, which is a
re-implementation of &lt;a href=&quot;https://github.com/stefanpenner/ember-app-kit&quot;&gt;Ember App
Kit&lt;/a&gt; for the Rails Asset Pipeline.&lt;/p&gt;

&lt;h4&gt;Robert Jackson&lt;/h4&gt;

&lt;p&gt;Robert is a Sr. Developer at DockYard. He is a member of the Ember Release Management Team and a significant contributor to Ember. He spends much of his free time helping maintain a number of Ember related open-source projects including: &lt;a href=&quot;https://github.com/emberjs/data&quot;&gt;Ember Data&lt;/a&gt;, &lt;a href=&quot;https://github.com/dockyard/ember-appkit-rails&quot;&gt;Ember Appkit Rails&lt;/a&gt;, &lt;a href=&quot;https://github.com/stefanpenner/ember-app-kit&quot;&gt;Ember App Kit&lt;/a&gt;, the &lt;a href=&quot;https://github.com/stefanpenner/ember-jj-abrams-resolver&quot;&gt;EAK/EAKR resolver&lt;/a&gt;, &lt;a href=&quot;https://github.com/emberjs/ember-rails&quot;&gt;ember-rails&lt;/a&gt;, &lt;a href=&quot;https://github.com/dockyard/ember-easyForm&quot;&gt;ember-easyForm&lt;/a&gt;, and &lt;a href=&quot;https://github.com/dockyard/ember-validations&quot;&gt;ember-validations&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Lin Reid is a DockYarder!</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/01/02/lin-reid-is-a-dockyarder" />
    <id>https://dockyard.com/blog/2014/01/02/lin-reid-is-a-dockyarder</id>
    <category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2014-01-02 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/lEkTCoq.jpg&quot; alt=&quot;Lin Reid&quot;&gt;&lt;/p&gt;

&lt;p&gt;Lin comes to us from Alaska. Normally that is all that you need to say
but Lin also brought us jerked-bear (actual Alaskan black bear) on his first day with us as an
intern. From there it was easy street. Lin&amp;#39;s published his own
&lt;a href=&quot;https://github.com/dockyard/stashable_params&quot;&gt;gem&lt;/a&gt;,
contributed back to several of our projects, and has been expanding his
developer horizons with Ember over the past few months. He is also the
&lt;em&gt;co-founder&lt;/em&gt; of &lt;a href=&quot;http://pizza-time.herokuapp.com&quot;&gt;Pizza Time&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow Lin on &lt;a href=&quot;https://twitter.com/linstula&quot;&gt;Twitter&lt;/a&gt; and on &lt;a href=&quot;https://github.com/linstula&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Robert Jackson is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/01/02/robert-jackson-is-a-dockyarder" />
    <id>https://dockyard.com/blog/2014/01/02/robert-jackson-is-a-dockyarder</id>
    <category term="announcement" label="Announcement"/><category term="office" label="Office"/>
    <published>2014-01-02 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/bI7Lcru.jpg&quot; alt=&quot;Robert Jackson&quot;&gt;
Today is Robert Jackson&amp;#39;s first day at DockYard. Robert is joining our
team as a Sr. Rails and Sr. Ember developer by way of Florida (but he&amp;#39;ll
soon be joining us in the Northeast). Robert is a member of the Ember
Release Management Team and has been saving my ass with several of our
open source Ember projects over the past few months.&lt;/p&gt;

&lt;p&gt;Follow Robert on &lt;a href=&quot;http://twitter.com/rwjblue&quot;&gt;Twitter&lt;/a&gt; and
&lt;a href=&quot;https://github.com/rwjblue&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Romina Vargas is a DockYarder!</title>
    <link rel="alternate" href="https://dockyard.com/blog/2014/01/02/romina-vargas-is-a-dockyarder" />
    <id>https://dockyard.com/blog/2014/01/02/romina-vargas-is-a-dockyarder</id>
    <category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2014-01-02 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/LVxKfWm.jpg&quot; alt=&quot;Romina Vargas&quot;&gt;&lt;/p&gt;

&lt;p&gt;Romina was a DockYard intern that we just recently hired to full-time!
Over the past few months Romina has taken on all of the challenges we&amp;#39;ve
thrown at her and excelled. Now she&amp;#39;s TDD&amp;#39;ing, Vim&amp;#39;ing, Tmux&amp;#39;ing,
Ember&amp;#39;ing with the best of them. She&amp;#39;s also the co-author of the
exciting new Ember application that is all the buzz: &lt;a href=&quot;http://pizza-time.herokuapp.com&quot;&gt;Pizza
Time&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rsocci&quot;&gt;Follow Romina on GitHub&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Lessons Learned: The First Two Years of Running a Software Consultancy</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/12/22/lessons-learned-two-years-of-running-a-dockyard" />
    <id>https://dockyard.com/blog/2013/12/22/lessons-learned-two-years-of-running-a-dockyard</id>
    <category term="opinion" label="Opinion"/><category term="business" label="Business"/><category term="consulting" label="Consulting"/>
    <published>2013-12-22 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Brian talks about what has worked, what has not worked, and the changes that have been made at DockYard during its first two years</summary>
    <content type="html">&lt;p&gt;This is an update of &lt;a href=&quot;/opinion/2012/06/21/lessons-learned-six-month-of-running-dockyard.html&quot;&gt;the previous post that reflected on the first six
months of DockYard&lt;/a&gt;.
A lot has changed over the past year and a half, and a lot has not. I
won&amp;#39;t do a point-by-point comparison to the previous post but I will
address some as well as some of the feedback I got at the time. But
first, let&amp;#39;s talk about revenue.&lt;/p&gt;

&lt;h2&gt;Revenue&lt;/h2&gt;

&lt;p&gt;After our first year we took in about $750,000 in revenue. DockYard
officially began in January of 2012  so we had a full calendar year to
earn. From what I&amp;#39;ve been told this is pretty good for the first year as
a consultancy. In our second year we broke $1,500,000 at the beginning
of December. I&amp;#39;m happy with that, we doubled revenue. I have set a
revenue goal of $2,500,000 for 2014. Assuming there are no major screw ups
next year we should exceed that goal.&lt;/p&gt;

&lt;p&gt;Revenue is great and all but kind of useless information without our
profit margin. We have averaged around 20% profit margin over the past
two years. This year we were averaging in the mid to high 20s before we
hit a lull at the end of November.&lt;/p&gt;

&lt;h3&gt;The Negative Stuff&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s get the negative stuff out of the way first so we can focus on positives
for the remainder of the post. We could have done better the previous year, we could have done better
this year. We lost money due to decisions that I made throughout the
past two years. Those choices include two bad clients, a mistake in the
direction of our growth, and a lack of experience of running a
conference.&lt;/p&gt;

&lt;h3&gt;Bad Clients&lt;/h3&gt;

&lt;p&gt;In the previous post I mentioned how DockYard nearly folded from the
start due to a bad client. That nightmare lasted for a year and half and
was finally settled in June of this year. It ended up being nearly a
$50,000 loss for us. I am convinced this is due entirely to poor legal
counsel; I cannot stress enough how important it is to have a competent
lawyer on your side. We didn&amp;#39;t have someone that was willing to fight
for us, it cost us big time. We have since retained the law firm of
&lt;a href=&quot;http://gesmer.com&quot;&gt;Gesmer Updegrove&lt;/a&gt;. They&amp;#39;re pricey, but it&amp;#39;s worth it.&lt;/p&gt;

&lt;p&gt;However, before we ever engaged with our current lawyer we unfortunately
had another run with a bad client. This time to the tune of $20,000.
That hit came this year. What is really strange is that I knew walking
into this deal it was going to end badly, and I voiced my concerns
internally to my people at the time but I still OK&amp;#39;d the deal and it
unfolded just as I thought it would. It was a dumb move and we paid the
price of it.&lt;/p&gt;

&lt;p&gt;One of the plans for DockYard was to quickly grow into the political
tech space in Washington, DC. I have experience working in political
tech, I brought on a guy who I worked with at the DNC, and we hired another
guy I worked with on a political campaign. We started making
connections. It didn&amp;#39;t work out. Three reasons:&lt;/p&gt;

&lt;h4&gt;Timing&lt;/h4&gt;

&lt;p&gt;Timing is everything I guess. Especially in political tech, we set out
on this effort right when the 2012 cycle ended. It was a ghost town, and
rightly so. There is no reason for campaigns or political groups to
spend money on development efforts when the next election cycle is two
years away. While we spoke with a lot of people that were interested in
what we could do from a technical perspective there simply were very
little groups without any budget at the time.&lt;/p&gt;

&lt;h4&gt;The People&lt;/h4&gt;

&lt;p&gt;During my time at the DNC I worked with some awesome people. Nathan Woodhull,
Chris Gill, Brent Kimmel, Leo Zhadanovsky, and Nicole Aro to name a few.
I&amp;#39;ve been lucky enough to work with a few of them since. Unfortunately I
also got to work with some really shitty people too. I don&amp;#39;t think its
their fault, the political tech space is a real drag. It doesn&amp;#39;t 
attract a lot of talented people because the money to work on the inside
is very bad compared with any other job out there. The tone you get is
that it is a privilege that you should be thankful for, and perhaps
that is the case. But that leaves a vacuum that gets filled with people
that frankly don&amp;#39;t know their ass from a hole in the ground. Many of these
people are now in charge of making technology decisions in many
organizations. I have no interest in working with those types of people
again, nor do I want to subject my employees to work with them.&lt;/p&gt;

&lt;h4&gt;Politics&lt;/h4&gt;

&lt;p&gt;I&amp;#39;ve always considered myself &amp;quot;on the Blue team&amp;quot; but the past year has
really pissed me off. NSA, Healthcare.gov, drone strikes, and the
President trying everything he can muster to go to war with Syria. I
walked into our Business Developer&amp;#39;s office one day and I said enough was
enough. I could not in good conscience do work for the Democratic Party
because of these issues.&lt;/p&gt;

&lt;h3&gt;Just Dumb Wasted Money&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://wickedgoodruby.com&quot;&gt;We ran a conference this year&lt;/a&gt; and due to my
lack of experience running an event like this (and to be honest, being
taken advantage of by the venue we held the conference at) we lost $15,000.&lt;/p&gt;

&lt;p&gt;There were also downtimes when we didn&amp;#39;t have enough money coming in,
but I will get into detail about this later in this post. (and the
changes we&amp;#39;ve made to hopefully avoid this in the future)&lt;/p&gt;

&lt;p&gt;Overall I am pretty proud with our revenue over the past two years.
We didn&amp;#39;t start with an &amp;quot;industry superstar&amp;quot; on our team or with a
significant open source project in our pocket, nor were we on the &amp;quot;inside&amp;quot; of
the Boston tech scene. We&amp;#39;ve built a very strong brand for ourselves
very quickly.&lt;/p&gt;

&lt;h3&gt;Open Source&lt;/h3&gt;

&lt;p&gt;This is still a financial loser for us. I don&amp;#39;t care what people say, that&amp;#39;s a
fact. However, &lt;a href=&quot;https://twitter.com/peteforde&quot;&gt;Pete Forde&lt;/a&gt; commented on
my last post and what he said was absolutely true: it will help you hire
good people. DockYard has been making a name for itself in the Ruby and
Ember open source world. We have a good number of projects that people
are actively using. I encourage all of our developers to contribute back
to not just our projects but projects we use on a regular basis.&lt;/p&gt;

&lt;h3&gt;Personnel&lt;/h3&gt;

&lt;p&gt;I&amp;#39;ve made missteps on hirings, that is also costly. I&amp;#39;ll get into this
later in the article.&lt;/p&gt;

&lt;p&gt;OK, enough with the negative stuff. Let&amp;#39;s get into what we did right.&lt;/p&gt;

&lt;h2&gt;Great Clients&lt;/h2&gt;

&lt;p&gt;We have had some awesome clients over the past year and a half. I am
pretty much happy with everyone we&amp;#39;ve had with the exception of the two
clients I mentioned above. We have kept a balance of Startups and
Enterprise, but we have been very careful about the people we work with.
This is how I have boiled it down to the clients we want to work with:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Can they afford us? If you think it is callous to put this as the
first thing we look for, then you are probably not someone we want to
work with. We are running a business and there are plenty of great ideas
out there and plenty of great people. But the sad fact is many of them
cannot afford to build the applications they dream of, at least not
through us. Financially vetting clients is very important. It makes no
sense to waste our time in contract negotiations with someone that
cannot afford our services. We try to discover this as soon as possible
so we don&amp;#39;t waste any of the client&amp;#39;s time either. We try to make the
best recommendation on the next steps they can take. We never take
equity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is this an application we want to work on? I would make this the 2nd
No. 1 if I could. While it is very important to make sure we have
clients that can pay us so we can pay our employees it is equally
important to make sure we have projects that our employees actually want
to work on. This is something that I butted heads over with our Business Developer
early on. He was not coming from a developer background and at the start
did not know what projects were good and which were shit, from an engineering
perspective. Consultancies are a feeding ground for other companies to
poach from. We try to retain our employees by paying well and by keeping
them on interesting and challenging projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is this a project that helps us grow? This is something we
have, over the past six months, started to think about when speaking
with clients. Is this a project we would be proud to put in our
portfolio? Is this a project we can write a case-study on? Is this a
project that helps us make a sales pitch to an even larger client?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we can stick to these three items when choosing clients I think we&amp;#39;ll
be fine. That is not always the case and from time to time we have had
to sacrifice up the chain. So the first to go is #3, then #2, and
finally #1 if we are desperate.&lt;/p&gt;

&lt;h2&gt;Our Tech Stack&lt;/h2&gt;

&lt;p&gt;While we started out as a Rails shop we have moved very quickly over the
past year to brand ourselves also as an &lt;a href=&quot;http://emberjs.com&quot;&gt;Ember&lt;/a&gt; shop.&lt;/p&gt;

&lt;p&gt;I believe in Ember as a technology, it is superior to any other
JavaScript framework out there in every way except for the learning
curve. I see many developers that I have known in the Boston area hate
on Ember. Good, let them. More for us. We also chose Ember for business
reasons.&lt;/p&gt;

&lt;p&gt;Competing with all of the other Rails shops in Boston is just stupid.
Down the street we have one of the most well know Rails consultancies in
the world (thoughtbot) and within a half a mile we have about 6 others
lesser-known ones. From an ability perspective we are just as good as
any of them, but then again that&amp;#39;s the point of Rails. There is no
technological advantage that any one shop has over another nowadays. We
all pretty much do the same &amp;quot;best practices&amp;quot; and use nearly the same tech
stack. There is nothing that distinguishes one shop from another. So we
have diversified our offerings.&lt;/p&gt;

&lt;p&gt;I chose Ember as a technology direction because it was, and still is,
incredibly undervalued in the market. If I was playing a short game in
our business I would invest in Angular, it is the tech-du-jour but a
year from now I seriously doubt that will be the case. While everyone
else is wasting their time specializing in Angular we&amp;#39;re building an
incredibly strong presence in the Ember world. When the scale tips we&amp;#39;re
going to be in a great position. At least that&amp;#39;s the theory. Time will
tell, maybe the next time I write on of these I&amp;#39;ll be bitching about how
wrong I was. We&amp;#39;ll see.&lt;/p&gt;

&lt;h2&gt;Hiring&lt;/h2&gt;

&lt;p&gt;For the most part I&amp;#39;ve been very lucky with the team I&amp;#39;ve hired.
Recently we just had our holiday party and I thought on my way to the
dinner that this is the team I&amp;#39;ve always wanted. I can&amp;#39;t imagine that is
a very common thing for people to think. And that&amp;#39;s not to say we
haven&amp;#39;t had missteps.&lt;/p&gt;

&lt;h3&gt;Finding The Right People&lt;/h3&gt;

&lt;p&gt;For us I hire for cultural fit. We have a good mix of senior and junior
talent. If we hire a junior developer I only hire people that show an
ability to learn fast. I really dislike white-board interviews so the
face-to-face interview is for me to get a sense of their personality.
Then I will ask some general knowledge questions to get a sense of where
they are at skill-wise. I will then send the candidate away for a week
and give them a project to create. I try to pick criteria that puts them
outside of their comfort zone. Have they done TDD before, have they done
Ember? I will ask them to challenge themselves and I will ask for access
to the GitHub repository. One indicator I use is how soon did the
candidate start this project? If it was started right away that shows an
eagerness to complete the work. Was is started and finished the night
before? This might show a tendency to procrastinate and get things in at
the last minute. While these may be outside factors I do ask about them
if they are extreme during the follow-up interview.&lt;/p&gt;

&lt;p&gt;Recently we have been able to build enough of a name for ourselves in
the development community where we have started to attract some good
senior development talent. We are putting a pause on hiring junior
developers and will likely focus on more senior developers for the next
year.&lt;/p&gt;

&lt;h3&gt;Firing People&lt;/h3&gt;

&lt;p&gt;I&amp;#39;ve gotten permission to talk about this from Russ. Russ was a
co-founder of DockYard and I fired him. It was around the time of the
first post but I didn&amp;#39;t want to reflect on it yet. In retrospect it was a
long-term mistake but perhaps the correct short-term decision. We were
not at the size when I was really thinking too long-term. I was not
getting from him what I needed and it was weighing me down mentally, but
this was my fault. I was not communicating to Russ properly what my
expectations were. Thankfully we&amp;#39;re still friends and grab drinks every
now and then. If the roles were reversed I don&amp;#39;t think I would be as
magnanimous.&lt;/p&gt;

&lt;p&gt;I&amp;#39;ve since fired two others. One was my fault, the other was not. It is
a strange thing to fire someone. People try to make it nice by saying
&amp;quot;let them go&amp;quot;, but in reality you&amp;#39;ve shit-canned them. When you are
employing someone, especially at a small company, you feel a sense of
responsibility for them. You are paying them money and provide them with
health care they use to take care of their family. I wish we could
magically double the salaries of all of our employees but of course we
cannot afford that. When it came time to firing someone it weighed on me
and I considered the implications. I never did it lightly, but
considering the alternative, each firing has turned out to be the correct move.
Even with Russ, he&amp;#39;s done much better without DockYard than he was doing
with DockYard. Sometimes its not a good fit, I am guilty of letting
things sit too long. I have learned to be quicker about acting upon
this.&lt;/p&gt;

&lt;h3&gt;Losing People&lt;/h3&gt;

&lt;p&gt;We have so far lost just one employee, one of our DC partners Chris
Gill. He got a job with the Department of Revenue that paid well beyond
what we could afford. I was actually pretty proud of him that he landed
it. I have left enough jobs in my career to know that I never want to be angry
at someone that has decided to leave DockYard. If it is time to go, it
is time to go. Considering the number of junior developers we have been training
up I would like to think of it as an accomplishment of ours to see
people &amp;quot;graduate&amp;quot; from DockYard and go on to do great things in the
industry. (but don&amp;#39;t leave us too quick!)&lt;/p&gt;

&lt;h2&gt;Business Development&lt;/h2&gt;

&lt;p&gt;In the summer of 2012 I was overwhelmed. I was Lead Developer, Business
Developer, Office Manager, and Everything Else* at DockYard. The most
important job I had was making sure new business was coming in. But
focusing on that was having a negative impact on the client projects I
was on as well as training any developers we had that required it. I
started a search for a Business Developer. At first I hatched a plan to
leverage the recruiters of Boston. It made sense: they already were
talking to companies but it was difficult for those companies to hire.
Why not just partner with DockYard and rent our services to those
companies? At 8% the math actually worked out in their favor, however none of
them bit. I&amp;#39;m still struggling with this one and I think it speaks to
the state of recruitment. It was a good business opportunity but they
could not think outside the box.&lt;/p&gt;

&lt;p&gt;So it was time to find someone for that position. I had never made a
non-technical hire before. I had no idea how to do that. I looked
specifically for &amp;quot;Business Developers&amp;quot; but that was a bust. I gave up
for a month or two then I realized that it was essentially a Sales
position. So I put an ad out for a someone in sales looking to take on a
larger role, a key role for the growth of a young company. I got about
50 resumes and brought in two people for interview. I liked them both
and settled on the one with the better references. It was a great
decision. Our Business Developer Dan Crowther has been huge for us. We butt
heads on a few things; he&amp;#39;s right sometimes and I&amp;#39;m right sometimes. But
the fact is we would not be where we are today without him.&lt;/p&gt;

&lt;p&gt;It took him about six months to really get comfortable with the
position, this is very common from what I&amp;#39;ve been told of those
transitioning into this position. He&amp;#39;s helped us open up business we
wouldn&amp;#39;t have known about otherwise. And most important I can focus on
other things.&lt;/p&gt;

&lt;p&gt;We sell DockYard on the quality of our work. While we started as a
technology company, design has become a large part of who DockYard is and
has gone a long way to help sell our brand.&lt;/p&gt;

&lt;h2&gt;Design&lt;/h2&gt;

&lt;p&gt;Since our first &amp;quot;real&amp;quot; contract with &lt;a href=&quot;http://openbay.com&quot;&gt;Openbay&lt;/a&gt; we
worked with an outside designer, Steven Trevathan. He was recommended to
me by two separate people. Steve along with his partner Logan Faerber
were starting their own consultancy Dobot. Steve and I got along 
well and I brought them back for a few more contracts. We bonded over
our mutual disdain for many of the people in the &lt;a href=&quot;http://www.cambridgecoworking.com/aboutc3.html&quot;&gt;C3 space at
CIC&lt;/a&gt; and so when we
finally got our own office last year I invited Steven and Logan to work
from there. We even brought them along to check out the office spaces
we were interested in. This past Spring it became obvious that we needed
someone full-time at DockYard to take ownership of our design. Likewise
Dobot was also looking for a lead engineer. It would be funny if it
wasn&amp;#39;t so stupid that we were literally sharing the same office, worked
together on several projects, and were still looking for one another. Steve and I
grabbed drinks and I laid it out: let&amp;#39;s do this. He agreed and we
brought Steve on as our Creative Director and a partner. Logan came on as a lead illustrator. It
is the best move we&amp;#39;ve made to date. Steve and Logan quickly took
ownership of the design direction of DockYard and have along with Amanda
and Angelo put out a &lt;a href=&quot;https://dockyard.com&quot;&gt;website that really represents who we
are&lt;/a&gt; and have also put together some amazing
designs for our clients.&lt;/p&gt;

&lt;p&gt;While earlier I mentioned how it was very difficult to differentiate
ourselves from other Rails shops, the one place we can totally do that
is with design. Ultimately design sells much better than engineering.
The engineering part of our contracts bring in more money, so we have to
make certain that the design contracts we pick up will convert to
engineering contracts. We look at design as the best Lead Generator we
could get. It has worked, very well.&lt;/p&gt;

&lt;h2&gt;Office Manager&lt;/h2&gt;

&lt;p&gt;This is one that I was told multiple times that I should do sooner than
later. I am very bad with context switching, I have to either do all
business stuff one day or all of the engineering. I cannot do both effectively.
After hiring Crowther I knew the next non-technical hire I wanted was an
office manager. What I did might be considered overboard.&lt;/p&gt;

&lt;p&gt;I put an ad on Craigslist. We got over 200 responses. I brought the list
down to around 100 and sent out invites and asked people to schedule
themselves for an interview through
&lt;a href=&quot;https://gb.youcanbook.me/&quot;&gt;YouCanBook.me&lt;/a&gt; I blocked out over two weeks
of time, and broke the interviews into 20 minute blocks. Over 60
interviews were scheduled. I ended up meeting with about 40 of people.
It was one of the crazier things I&amp;#39;ve done but this was a position I had
no idea how to hire and the only way I could figure to find the right
person was to see a ton of candidates and waited to see what stuck. The
person we hired was the 2nd person to walk through the door, Mariel
Ebrahimi. We got real lucky, and I think I even came out of that
interview and told everyone that we were probably going to hire her.
However, considering she was only the 2nd candidate I still went through
the next two weeks of interviews. It became obvious that she was well
beyond anybody else coming in and over the past few months she has kept
DockYard running smoothly. Being able to let go of these small things in
the office is incredibly freeing and has allowed me to focus on the
bigger picture.&lt;/p&gt;

&lt;p&gt;I have been toying with the idea of hiring a Project Manager in Boston.
We did that before in Washington, DC but we were in a very different position that
we are now and I think the position only works for us, at our size, in
Boston. I am currently running PM on most projects, at least to a
certain degree. I allocate resources, and assign roles. Developers at
DockYard look to me for what they should be doing next. It&amp;#39;s time
consuming and only gets worse as we grow. We&amp;#39;ll see what happens in the
next few months.&lt;/p&gt;

&lt;h2&gt;Building Our Own Products&lt;/h2&gt;

&lt;p&gt;We&amp;#39;ve tried it once and we failed. That simple. We failed for several
reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We could not work on the product consistently. This killed us. We
were putting in days here and there in between client work. I was
putting in hours on the weekend and this was burning me out for the rest
of the week.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It was not an idea that was very good beyond concept. We built out a
marketplace for Heroku called
&lt;a href=&quot;https://github.com/dockyard/igata&quot;&gt;Igata&lt;/a&gt; It would allow developers to
sell pre-baked applications for deployment on Heroku. I liked the
challenge of building the initial technology. But when I began to think
about the long term implications of maintaining a marketplace
application I lost all interest.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Heroku was too much of an obstacle. I actually went out to Heroku and
met with some of their people to pitch them on the idea. They liked
it but it became clear that if we really wanted to make money we should
just make our own Heroku and not lose the money on hosting. Then it was
an easy mental jump to &amp;quot;let&amp;#39;s forget about this marketplace and just
compete with Heroku&amp;quot; which of course is a dumb idea.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So we bailed on the application and open sourced it. We are going to
attempt another product built, this time we are going to save up a
financial war chest so we can dedicate the proper amount of time to the project.
I don&amp;#39;t mind losing money on projects like this. They are fun to build
and I think we come out the other end as a better shop once we dog food
our own process.&lt;/p&gt;

&lt;h2&gt;Getting Our First Office&lt;/h2&gt;

&lt;p&gt;I was pretty annoyed with all of the entrepreneurial bullshit that was
going on in the CIC in Cambridge. It is a terrible working environment,
especially if you are a consultancy. You get bugged all the time by the
worst people. The space is &lt;strong&gt;incredibly&lt;/strong&gt; loud. If you go there to work
on the weekends it&amp;#39;s fantastic. But it became obvious very quickly that
we needed our own office. We worked with &lt;a href=&quot;https://twitter.com/jfrisch21&quot;&gt;Jon
Frisch&lt;/a&gt; at &lt;a href=&quot;http://www.t3advisors.com/&quot;&gt;T3
Advisors&lt;/a&gt;. We were growing and we need
space to grow &lt;em&gt;into&lt;/em&gt;. We decided upon a 2,200 square foot 2nd floor space
in Downtown Crossing. I always wanted an office there because of how
centrally located it was. Thankfully, Downtown Crossing ends up being
much cheaper real-estate than many of the other places around Boston 
(although this is already changing).&lt;/p&gt;

&lt;p&gt;We had some difficulty moving in. We were supposed to start the build-out
in July of 2012. I was getting married in late August. The owner kept
deflecting us, and deflecting. I went on my honeymoon and when I got
back I asked him what the deal was. He said, &amp;quot;OK, it&amp;#39;s no longer an
active crime scene so I can tell you what happened.&amp;quot;&lt;/p&gt;

&lt;p&gt;It turns out that our office is a floor above a jewelery store. The
floor in our office is concrete. Two guys broke down a side door to the
vacant space, brought some mini-jackhammers and drilled a man-size hole
into the store below. They then repelled down with ropes and started to
clean the place out. There were some silent alarms that were set off and
they got busted. Exactly why it took them 2 months to clear the place to
allow us to build I don&amp;#39;t know. But considering how crazy the story is I
was OK with it.&lt;/p&gt;

&lt;p&gt;Anyway, we finally got into the space in October of 2012. Thankfully no
more jewelery heists have happened. We host a lot of community events at
our office and I&amp;#39;m really happy with that. Currently we organize &lt;a href=&quot;http://www.meetup.com/Boston-Ember-js/&quot;&gt;Boston
Ember&lt;/a&gt;, &lt;a href=&quot;http://openhack.github.io/boston/&quot;&gt;Boston OpenHack&lt;/a&gt;, &lt;a href=&quot;http://www.meetup.com/uxboston/&quot;&gt;UX Boston&lt;/a&gt;, run classes for &lt;a href=&quot;http://www.girldevelopit.com/chapters/boston&quot;&gt;Girl Develop It Boston&lt;/a&gt;, and
host &lt;a href=&quot;http://www.meetup.com/Boston-PostgreSQL-Users-Group-BPUG/&quot;&gt;Boston
Postgres&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Starting Over&lt;/h2&gt;

&lt;p&gt;If I had to start DockYard from scratch today I would do it differently.
The number one thing I would do different is not agree to a partnership
until 6 months out. I would have awarded co-founder status to those
that started, but I would have held off on awarding partnerships
until everyone settled into their roles. I think when you first get going you don&amp;#39;t really
understand what those roles are. Assigning roles on day zero
and expecting everyone to just stick to these roles is not realistic if
this is everyone&amp;#39;s first rodeo. Trial by fire is the best way to define
the roles. Once that is done then the partnership can be established.
Perhaps someone that previously thought being partner was a good idea
was not actually interested in the added responsibility? Perhaps someone
you didn&amp;#39;t think was &amp;quot;partner material&amp;quot; ends up being one of your key
people and that should be rewarded.&lt;/p&gt;

&lt;p&gt;I would also hire a little more slowly than we did at first. I have not
yet been able to pay myself what I&amp;#39;ve set my salary to. The first year I
paid myself 25% of that salary. This year I&amp;#39;ve hit my goal of paying
myself 50%. Next year I hope to hit 100% of that goal. Thankfully I&amp;#39;ve
got a wife that makes a good living and we&amp;#39;ve been able to lean on that
when I&amp;#39;ve needed to take myself off of payroll. If our situation were
different I am not confident that DockYard would be around today, at
least not in its currently form. I&amp;#39;ve been able to take risks that
others might not be able to.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Any success we have had is due in part to not just the great team we
have but honestly sometimes just luck. There have been several times in
the past two years where I have not been able to sleep due to the stress
of thinking how we were going to make the next few payrolls. Every time
we got lucky, someone came along at the right moment and bailed us out.
I would like to think we are out of those woods, we&amp;#39;ll see.&lt;/p&gt;

&lt;p&gt;One way I have changed how DockYard operates is moving away from always
new clients to retaining clients. I had lunch with &lt;a href=&quot;https://www.assembla.com/spaces/andy/wiki&quot;&gt;Andy
Singleton&lt;/a&gt; and he stressed
and convinced me that we were throwing away money by always looking
for new clients. The really successful consultancies had several large
contracts that would span multiple years. It was obvious but I had not
seen it until it was spelled out for me. So we are going to look to
retain and provide ongoing services for our existing clients. If
someone is reading this and looking to get started that was probably
one of our biggest mistakes over the past two years; find a client that
you might even need to take a financial hit on but is always there to
help you keep the lights on. Looking back it seem crazy that we were
able to not just survive but thrive given out direction of always
looking for greenfield projects.&lt;/p&gt;

&lt;p&gt;In the next few years I don&amp;#39;t want to see the same rate of growth we&amp;#39;ve
previously had. I&amp;#39;ve said several times to my team I don&amp;#39;t want to grow
to more than 20. Any more than that and we&amp;#39;ll have to consider some
serious restructuring of the company. I also feel at that number the
small team we have starts to feel more like a &amp;quot;real company&amp;quot;. We just
recently made an offer to a new member of our team that will be joining
in January. I have not met her yet and that is strange to me, but is
also an indicator that we have grown to that point that these things
will happen.&lt;/p&gt;

&lt;p&gt;I look forward to hearing the feedback from this article. I&amp;#39;m sure there
will be people that disagree with some of the things I&amp;#39;ve said and the
decisions we&amp;#39;ve made.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Simple Property Enum Cycling in Ember</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/12/19/ember-enum-property-cycler" />
    <id>https://dockyard.com/blog/2013/12/19/ember-enum-property-cycler</id>
    <category term="ember" label="Ember.js"/>
    <published>2013-12-19 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A quick demo of cycling between a set of values</summary>
    <content type="html">&lt;p&gt;This is a quick one. I needed to cycle between the values in a set.
Toggling between &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; in Ember is easy enough with the
&lt;code&gt;toggleProperty&lt;/code&gt; function but I had several properties I wanted to cycle
between. So last night I wrote a simple function poorly named:
&lt;code&gt;cycleEnumProperty&lt;/code&gt;. You pass it the property you want to act upon and
the enum set to cycle. If the property is currently empty or if the
property matches the last value in the set the property will be set to
the first value, otherwise the property will be set to the next value.
Try it out:&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;jsbin-embed&quot;
href=&quot;http://emberjs.jsbin.com/agaKuCoL/1/embed?js,output&quot;&gt;Ember
Starter Kit&lt;/a&gt;&lt;script
src=&quot;http://static.jsbin.com/js/embed.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Be A Blunt Axe</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/12/18/be-a-blunt-axe" />
    <id>https://dockyard.com/blog/2013/12/18/be-a-blunt-axe</id>
    <category term="design" label="Design"/><category term="illustration" label="Illustration"/><category term="art" label="Art"/>
    <published>2013-12-18 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Logan Faerber</name></author>
    <summary>Giving good feedback without being too aggressive.</summary>
    <content type="html">&lt;h2&gt;Be A Blunt Axe&lt;/h2&gt;

&lt;p&gt;Something that was taught to us early on in College was how to make a &amp;quot;compliment sandwich.&amp;quot; Iâm sure many of you have heard this term before, but for those of you who havenât, it&amp;#39;s a communication tool that can keep yourself humble when confronted with the daunting task of giving others critical feedback on their work. &lt;/p&gt;

&lt;p&gt;The idea is that you as the critic would point out a positive aspect about their work or concept, the top layer of bread if you will. Then youâd follow this by mentioning something they could improve upon, which is the meaty and true substance of the discussion. At the end youâd conclude by providing another positive aspect, a la the last bit of bread. The reason we had to come up with this step-by-step process when approaching a critique environment was to avoid hurting anyoneâs feelings. Rather than declaring an idea as stupid or bad, which honestly helps to accomplish nothing aside from increase the size of a criticâs ego, we had now formulated a way of give important and in-depth feedback that would actually help to improve an idea by simply being kind and genuinely interested in helping. Keeping to this method, people were much more adept to make the suggested improvements rather than declare themselves a failure, giving up before theyâve even begun to start. &lt;/p&gt;

&lt;p&gt;It&amp;#39;s important to remember that your feedback can and should be honest and frequent, but kindness prevails over being an asshole (every time). By being empathetic to the person receiving the critique, you get a better sense of what&amp;#39;ll help them improve, rather than just tearing them down. With this, your critiques become genuine and no longer appear as a means to stroke an inflated ego. Without this, the whole world would be filled with broken hearts and ego-powered douche-bags. As they say, &amp;quot;an eye for an eye makes the whole world blind&amp;quot;. Let&amp;#39;s keep our eyes and hearts intact.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Introducing easydir.vim</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/12/08/introducing-easydir-vim" />
    <id>https://dockyard.com/blog/2013/12/08/introducing-easydir-vim</id>
    <category term="workflow" label="Workflow"/><category term="vim" label="Vim"/>
    <published>2013-12-08 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>A Vim plugin that allows you create directories and files at the same time!</summary>
    <content type="html">&lt;p&gt;One of the things that I wish Vim had by default is the ability to create
directories and files at the same time. Last month at our local
&lt;a href=&quot;http://openhack.github.io/&quot;&gt;OpenHack meetup&lt;/a&gt;, I had a conversation about
it with a fellow developer and we both concluded that it wouldn&amp;#39;t be too
difficult to write something up.&lt;/p&gt;

&lt;p&gt;Well, I&amp;#39;m happy to introduce &lt;a href=&quot;https://github.com/dockyard/vim-easydir&quot;&gt;easydir.vim&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;It adds to the functionality of &lt;code&gt;:new&lt;/code&gt;, &lt;code&gt;:edit&lt;/code&gt;, &lt;code&gt;:write&lt;/code&gt;, and more.&lt;/p&gt;

&lt;p&gt;Here are some quick examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit a new file inside of a previously nonexistent directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:e new_directory/new_file.txt

# Write some things to &amp;quot;new_file.txt&amp;quot; and save it.

:w

# The directory &amp;quot;new_directory/&amp;quot; and the file &amp;quot;new_file.txt&amp;quot;
# are saved!
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Open the new directory and file into a split window.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:sp another_directory/another_file.txt

# Write to &amp;quot;another_file.txt&amp;quot; and save the file.

:w

# another_directory/another_file.txt is saved!
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Super nested directories&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:n thank/you/sir/may/i/have/another.txt

# Write some things to &amp;quot;another.txt&amp;quot; and save it.

:w
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The directories and files will be saved under your current project&amp;#39;s directory.&lt;/p&gt;

&lt;p&gt;Thanks for checking it out and enjoy!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Never Stop Exploring</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/12/06/always-be-exploring" />
    <id>https://dockyard.com/blog/2013/12/06/always-be-exploring</id>
    <category term="design" label="Design"/><category term="illustration" label="Illustration"/><category term="art" label="Art"/>
    <published>2013-12-06 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Logan Faerber</name></author>
    <summary>Being true to yourself and creating passionate work.</summary>
    <content type="html">&lt;h2&gt;Never Stop Exploring&lt;/h2&gt;

&lt;p&gt;Over the years, many artists seem to have fallen into a creative rut within their chosen career path. Some may have found a comfortable day job that sufficiently pays the bills. Others simply retired early, claiming to have burnt out creatively, and chose to throw in the artistic towel for a simpler lifestyle, one far less plagued by self doubt and critical objections, Iâm sure. Whatever the reason is, we as a society are more often selecting to pursue comfort over curiosity and I believe itâs hurting the progression of our personal artistic expression in both our culture and as individuals.&lt;/p&gt;

&lt;p&gt;By choosing to accept whatâs handed to you by media, youâre merely absorbing otherâs ideas or predefined popular interests that have become media friendly rather than participating as part of the cultural influence. This accounts for many of the current trends that appear in graphic design, illustration, web design, music, and movies these days. How else would you have ended up with Independence Day, Mars Attacks, and Men in Black hitting the top box office charts all within the same year? You couldnât. Aliens and end of the world scenarios were accepted as hot topics at the time, but are any of them truly remembered as works of art? I would argue the answer to be, âNoâ. What makes something a genuine work of art is the passion with which it is made. A fresh and deeply personal idea that attempts to either break the rules of the medium or painstakingly craft them to best suit your particular need. &lt;/p&gt;

&lt;p&gt;For example, as soon as iOS7 was shown to the public, a majority of the design communityâs reaction was negative. But as soon as this same operating system was made public and write-ups began appearing online from major figureheads in the industry, peopleâs views started to change, as did their designs. The same people who appeared to be so opposed to this recent announcement were beginning to cater their latest designs to having an extremely minimal feel, embracing extra thin typefaces and overly saturated primary colors. While I for one have definitely come to appreciate specific things about the iOS7 operating system, there are definitely things about itâs design that are not necessarily applicable to other interface scenarios. In short, just because a big company is successful with their design doesnât mean itâs the right fit for your project. No oneâs remembered for who theyâve copied. Theyâre remembered for what innovations theyâve made or new ideas theyâve brought to the table. &lt;/p&gt;

&lt;p&gt;Whether this trend is a culturally specific problem or something that has plagued mankind for years, Iâm unsure. What I am sure of though is that I for one donât ever want to find myself in this predetermined rut. I think everyone has great ideas, and itâs important for them to take the time to properly express them. Itâs a matter of finding the motivation in yourself to make it happen and take the risk of making it public. As the great Bill Nye said, âEveryone you will ever meet knows something you don&amp;#39;tâ.&lt;/p&gt;

&lt;p&gt;I for one keep a persistent list of ideas that I want to explore, both in a physical journal and on &lt;a href=&quot;https://www.wunderlist.com/en/&quot;&gt;Wunderlist&lt;/a&gt;, just so that no matter how random the idea may seem, I can at the very least document it to be reviewed at a later date. When I do have down time between projects, I never have to search too hard for a new one to get started. For instance, my current side project is to keep an ongoing list of fictional band names that my friends and I have collected over the years and make actual merchandise out of them as if they were real bands. I treat these projects like tiny experiments and allow myself to try new things, technically and mentally. That way, when I do return to my other projects, they never feel stale. Iâm once again excited to work on them and have a new set of skills or ideas to help make them even better. &lt;/p&gt;

&lt;p&gt;This is why I think itâs important that no matter what you do, whether itâs a full time design job, freelance illustration, or something far removed from the art profession you had originally pursued, to always keep your mind fresh with new ideas. Explore all possibilities and try new things whenever you can. The more you create, the more apt you are to legitimately think outside the box, rather than work within itâs constraints. And that, my friends is how you will be remembered, for being true to yourself and creating genuine, passionate work.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Buffers, Windows, Tabs... Oh My! Part 2: Vim Windows</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/11/27/vim-windows" />
    <id>https://dockyard.com/blog/2013/11/27/vim-windows</id>
    <category term="workflow" label="Workflow"/><category term="vim" label="Vim"/>
    <published>2013-11-27 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>A painless tutorial on Vim windows</summary>
    <content type="html">&lt;p&gt;In the second part of this series, we&amp;#39;ll be covering Vim windows. Windows are simply
the &lt;strong&gt;viewports&lt;/strong&gt; into &lt;a href=&quot;http://reefpoints.dockyard.com/2013/10/22/vim-buffers.html&quot;&gt;buffers&lt;/a&gt;
and I&amp;#39;m 110% sure that they are a huge part of your daily workflow.&lt;/p&gt;

&lt;p&gt;Yes, there are numerous plugins that make our lives a lot easier, but let&amp;#39;s
dive into a powerful defaults that Vim offers us.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ll first cover the basics, and then learn some neat window management commands.&lt;/p&gt;

&lt;h2&gt;Starting a Vim Session&lt;/h2&gt;

&lt;h3&gt;One File&lt;/h3&gt;

&lt;p&gt;Vim windows are not complicated to use; if you want to open a file, &lt;code&gt;file_one.txt&lt;/code&gt;, simply:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ vim file_one.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Multiple Files&lt;/h3&gt;

&lt;p&gt;If you want to open multiple files, &lt;code&gt;file_one.txt&lt;/code&gt;, &lt;code&gt;file_two.txt&lt;/code&gt;, and &lt;code&gt;file_three.txt&lt;/code&gt;, you can
do the following:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ vim file_one.txt file_two.txt file_three.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This opens the first file, &lt;code&gt;file_one.txt&lt;/code&gt;, into a window.
Files &lt;code&gt;file_two.txt&lt;/code&gt; and &lt;code&gt;file_three.txt&lt;/code&gt; are opened as inactive buffers.&lt;/p&gt;

&lt;h3&gt;Multiple Horizontal Splits&lt;/h3&gt;

&lt;p&gt;Say you want to view multiple files at once. Good news! You can
open all files and place them into &lt;strong&gt;horizontal splits&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ vim -o file_one.txt file_two.txt file_three.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Multiple Vertical Splits&lt;/h3&gt;

&lt;p&gt;Don&amp;#39;t like horizontal splits? Better news! You can open them all as &lt;strong&gt;vertical splits&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ vim -O file_one.txt file_two.txt file_three.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Within a Vim Session&lt;/h2&gt;

&lt;p&gt;There are two main arrangements for splitting windows, vertical and horizontal. Let&amp;#39;s say
we&amp;#39;re editing a file and want to open up another file. We can do the following:&lt;/p&gt;

&lt;h3&gt;Horizontal Splits&lt;/h3&gt;

&lt;p&gt;This will open &lt;code&gt;another_file.txt&lt;/code&gt; as &lt;strong&gt;horizontal split&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:split another_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can use this abbreviation:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:sp another_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In addition, you can specify how large the new split will be by passing
in a numerical value. This value will represent the line numbers shown within the
split.&lt;/p&gt;

&lt;p&gt;For example, this will reveal 25 lines of &lt;code&gt;another_file.txt&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:25sp another_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Lastly, you can open a &lt;strong&gt;split&lt;/strong&gt; window with &lt;code&gt;CTRL-W s&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Vertical Splits&lt;/h3&gt;

&lt;p&gt;You can open files as &lt;strong&gt;vertical splits&lt;/strong&gt; as well.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:vsplit another_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Which is abbreviated as:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:vsp another_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Vertical splits&lt;/strong&gt; can also take in a numerical value, which corresponds to the
character width of the column.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:30vsp another_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Finally, you can open a &lt;strong&gt;vertical split&lt;/strong&gt; with &lt;code&gt;CTRL-W v&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;New Files&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s create a new file.&lt;/p&gt;

&lt;p&gt;Use, &lt;code&gt;:new&lt;/code&gt; to create a new file inside the current window.
After you save the file, it will be created within your current directory.
You can also use the abbreviation &lt;code&gt;:n&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:n new_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If we specify the path, we can also create files inside existing directories.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:n ../existing_dir/new_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;:vnew&lt;/code&gt; or &lt;code&gt;:vne&lt;/code&gt; to create a new file inside a new &lt;strong&gt;vertical split&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:vne new_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Lastly, we can use &lt;code&gt;CTRL-w n&lt;/code&gt; to create a new file inside a &lt;strong&gt;horizontal split&lt;/strong&gt;.
Note that we have not specified a file name. Upon saving the file with &lt;code&gt;:w&lt;/code&gt;, we
can give the file a name. Such that:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# CTRL-w n

:w this_is_a_new_file.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Switching Windows&lt;/h3&gt;

&lt;p&gt;Switching windows ain&amp;#39;t hard either!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CTRL-w h&lt;/code&gt; = Switch to the window to the left&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w j&lt;/code&gt; = Switch to the window below&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w k&lt;/code&gt; = Switch to the window above&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w l&lt;/code&gt; = Switch to the window to the right&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Moving Windows&lt;/h3&gt;

&lt;p&gt;I&amp;#39;ve realized that window placement is incredibly useful
when pairing with another person. Here&amp;#39;s are a some ways to adjust
the windows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CTRL-w T&lt;/code&gt; = Move current window to a new tab&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w r&lt;/code&gt; = &lt;em&gt;Rotates&lt;/em&gt; the windows from left to right - only if the windows
are split vertically&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w R&lt;/code&gt; = &lt;em&gt;Rotates&lt;/em&gt; the windows from right to left - only if the windows
are split vertically&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w H&lt;/code&gt; = Move current window the far left and use the full height of the screen&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w J&lt;/code&gt; = Move current window the far bottom and use the full width of the screen&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w K&lt;/code&gt; = Move current window the far top and full width of the screen&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w L&lt;/code&gt; = Move current window the far right and full height of the screen&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Resizing Windows&lt;/h3&gt;

&lt;p&gt;Sometimes windows open up funny or are rendered incorrectly after separating from
an external monitor. Or maybe you want to make more room for an important file.&lt;/p&gt;

&lt;p&gt;We can easily solve those problems with the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CTRL-w =&lt;/code&gt; = Resize the windows &lt;em&gt;equally&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w &amp;gt;&lt;/code&gt; = Incrementally increase the window to the right

&lt;ul&gt;
&lt;li&gt;Takes a parameter, e.g. &lt;code&gt;CTRL-w 20 &amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w &amp;lt;&lt;/code&gt; = Incrementally increase the window to the left

&lt;ul&gt;
&lt;li&gt;Takes a parameter, e.g. &lt;code&gt;CTRL-w 20 &amp;lt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w -&lt;/code&gt; = Incrementally decrease the window&amp;#39;s height

&lt;ul&gt;
&lt;li&gt;Takes a parameter, e.g. &lt;code&gt;CTRL-w 10 -&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRL-w +&lt;/code&gt; = Incrementally increase the window&amp;#39;s height

&lt;ul&gt;
&lt;li&gt;Takes a parameter, e.g. &lt;code&gt;CTRL-w 10 +&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;That was a lot to cover, but I do believe incorporating these commands into
your workflow will prove pretty helpful. Thanks for reading!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Think</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/11/15/think" />
    <id>https://dockyard.com/blog/2013/11/15/think</id>
    <category term="ruby" label="Ruby"/><category term="community" label="Community"/><category term="opinion" label="Opinion"/>
    <published>2013-11-15 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Don&#39;t do what others tell you to do without thinking about it</summary>
    <content type="html">&lt;p&gt;Ever since &lt;a href=&quot;http://wickedgoodruby.com/2013/speakers/matt_aimonetti&quot;&gt;Matt Aimonetti&amp;#39;s talk at
Wicked Good Ruby&lt;/a&gt;
on there being such thing as bad code, I&amp;#39;ve felt I&amp;#39;ve
needed to write a blog post about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Cargo_cult&quot;&gt;cargo
culting&lt;/a&gt; that happens in
the development world.&lt;/p&gt;

&lt;h2&gt;Sandi Metz&amp;#39;s Rules&lt;/h2&gt;

&lt;p&gt;Back in January, &lt;a href=&quot;http://rubyrogues.com/087-rr-book-clubpractical-object-oriented-design-in-ruby-with-sandi-metz/&quot;&gt;Sandi Metz was on Ruby
Rogues&lt;/a&gt;
to discuss her book, &lt;strong&gt;&lt;a href=&quot;http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330/&quot;&gt;Practical Object-Oriented Design in Ruby&lt;/a&gt;&lt;/strong&gt;.
Out of this conversation came &amp;quot;&lt;a href=&quot;https://gist.github.com/henrik/4509394&quot;&gt;Sandi Metz&amp;#39;s
rules&lt;/a&gt;&amp;quot;. Many
in the Ruby community took these rules as gospel, without knowing the
context in which these rules were created.&lt;/p&gt;

&lt;p&gt;The rules, for those unfamilar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your class can be no longer than 100 lines of code&lt;/li&gt;
&lt;li&gt;Your methods can be no longer than five lines of code&lt;/li&gt;
&lt;li&gt;You can pass no more than four parameters and you can&amp;#39;t just make it one big hash&lt;/li&gt;
&lt;li&gt;When a call comes into your Rails controller, you can only instantiate one object to do whatever it is that needs to be done&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sandi joined Matt during his talk at Wicked Good Ruby and &lt;a href=&quot;http://www.youtube.com/watch?feature=player_embedded&amp;amp;v=VO-NvnZfMA4#t=1380&quot;&gt;gave some background to the
story of her rules&lt;/a&gt;.
To paraphase Sandi, at the time she was working with a group that had multi-thousand line controllers with
multi-hundred line methods. These controllers and methods represented
one end of a spectrum, which made code incredibly hard to read and maintain.
They were begging Sandi for guidelines with which they could try to
correct this problem. What she did was create a set of rules that
lived on the opposite side of the extreme, to force them to meet
somewhere in the middle.&lt;/p&gt;

&lt;p&gt;In reality, these rules are a different way of looking at rules many of
us strive for in the first place. An example: The 100 lines per class
rule is really forcing you to create classes with the &lt;a href=&quot;https://en.wikipedia.org/wiki/Single_responsibility_principle&quot;&gt;Single
Responsibility Principle&lt;/a&gt; in mind.&lt;/p&gt;

&lt;p&gt;My issue is not with these rules as they exist, but with the
community&amp;#39;s cargo culting of these rules and treating them as The Four
Commandments. I don&amp;#39;t have an issue with you following them, as long as
you understand why they exist, and you feel as though they are
principles you believe in. Don&amp;#39;t just make five line methods because
Sandi said so, and if you follow these rules, you feel like you&amp;#39;ll be a
great developer. Adhering to Sandi&amp;#39;s rules does not make one great, it&amp;#39;s
understanding where these, or any rules, should and shouldn&amp;#39;t apply.
Sometimes a method that spans more than five lines will be more readable
and maintainable than the same method spread across five or six 5-line
methods. Striking that balance is where the power lies.&lt;/p&gt;

&lt;h2&gt;REMOTE&lt;/h2&gt;

&lt;p&gt;37signals just published
&lt;a href=&quot;http://www.amazon.com/Remote-Office-Required-Jason-Fried/dp/0804137501/&quot;&gt;REMOTE&lt;/a&gt;, a book about
the benefits of allowing remote workers. I don&amp;#39;t disagree that
working remote has many benefits. At DockYard, we work from home from time
to time. We also strive to have people in the office more often than
not, not because Brian doesn&amp;#39;t think we aren&amp;#39;t working when we aren&amp;#39;t in
the office, but because it enables greater collaboration.&lt;/p&gt;

&lt;p&gt;DockYard is a consultancy; we have client work with deadlines we have to
meet. With having our developers and designers in the office together more
often than not, it removes the latency from discussing issues. I can
walk over to Steve and we can hash out an issue in a few minutes. If we
were all remote, I&amp;#39;d have to ping him on HipChat, hope he&amp;#39;s at his desk,
try to go over the issue text-only until we realize we need to have a
Google Hangout, etc. It makes more sense for us to be in the same place.&lt;/p&gt;

&lt;p&gt;The other benefit of DockYard working from the office is that our junior
developers enjoy the same face-to-face benefits. Also, body language
makes a huge difference when teaching or learning topic. When someone pauses,
has a slightly puzzled look on their face and says &amp;quot;....Ok&amp;quot;, it easy to
realize that a bit more background on the topic will really let them
grasp the topic, but an &amp;quot;ok&amp;quot; in HipChat removes all the body language we
could leverage.&lt;/p&gt;

&lt;p&gt;Removing the latency between a junior developer having a
question and getting the answer is crucial. If a junior developer has a
question that&amp;#39;s a show stopper, they can feel helpless while they wait
for someone to be around to answer that question. That helplessness is
killer; it makes someone feel like they aren&amp;#39;t helping, and can
potentially prevent them from asking other questions. If the that delay
is interpreted as the senior developer blowing them off, they will be
less inclined to ask questions in the future, hurting both themselves
and the team.&lt;/p&gt;

&lt;p&gt;A product company that employs experts (or creators) of a framework has
a much different situation, where working remote makes a lot more sense.
The conversations they have will be at a different level. They&amp;#39;ll all
have intimate knowledge of the code base, and so a few questions back
and forth or a quick Google Hangout achieves a great deal. The
conclusion was a result of the context they exist in. Remote workers
work great for them because they have the perfect mix of experts in
their domain; are working on products, which have very different
requirements and issues of client work; and have a customer support
group, which don&amp;#39;t necessarily need to collaborate while working a
customer through issues.&lt;/p&gt;

&lt;h2&gt;Figure Out What Works for YOU&lt;/h2&gt;

&lt;p&gt;In no way am I saying you should all work in the same office and
disregard Sandi&amp;#39;s rules. What I&amp;#39;m asking of the community is a bit of
critical thought. Just because someone smart said one thing, it doesn&amp;#39;t
mean it&amp;#39;s gospel. Realize that experience has led that person to that
conclusion, weigh your experience against it, and apply it if you can.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s just not hope that the gods give us food because we made bamboo
airplanes. Let&amp;#39;s realize that moving to XYZ comes with both drawbacks and
benefits, not just the benefits that everyone is touting.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Introducing Capybara-Extensions</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/11/11/capybara-extensions" />
    <id>https://dockyard.com/blog/2013/11/11/capybara-extensions</id>
    <category term="testing" label="Testing"/><category term="ruby" label="Ruby"/>
    <published>2013-11-11 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Michael Dupuis</name></author>
    <summary>Write more descriptive tests with additional finders and matchers for Capybara.</summary>
    <content type="html">&lt;p&gt;Today we&amp;#39;re happy to announce &lt;a href=&quot;https://github.com/dockyard/capybara-extensions&quot;&gt;CapybaraExtensions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Testing with Capybara&lt;/h2&gt;

&lt;p&gt;We love &lt;a href=&quot;https://github.com/jnicklas/capybara&quot;&gt;Capybara&lt;/a&gt; at DockYard. We use it for virtually all of our integration tests and
rely on it for writing tests that not only replicate how users flow
through an application, but also for how they interact with page
elements.&lt;/p&gt;

&lt;p&gt;Briefly, let&amp;#39;s take a look at a Rails application with and without
Capybara. Without Capybara, inheriting from &lt;code&gt;ActionDispatch::IntegrationTest&lt;/code&gt; provides
some helpful &lt;code&gt;RequestHelpers&lt;/code&gt; like &lt;code&gt;get&lt;/code&gt;, which takes a path, some
parameters, and headers (via &lt;a href=&quot;http://guides.rubyonrails.org/testing.html#integration-testing-examples&quot;&gt;RailsGuides&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test_helper&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;UserFlowsTest&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActionDispatch&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;IntegrationTest&lt;/span&gt;
  fixtures &lt;span class=&quot;symbol&quot;&gt;:users&lt;/span&gt;

  test &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;login and browse site&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;# login via https&lt;/span&gt;
    https!
    get &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/login&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    assert_response &lt;span class=&quot;symbol&quot;&gt;:success&lt;/span&gt;

    post_via_redirect &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/login&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;username&lt;/span&gt;: users(&lt;span class=&quot;symbol&quot;&gt;:david&lt;/span&gt;).username, &lt;span class=&quot;key&quot;&gt;password&lt;/span&gt;: users(&lt;span class=&quot;symbol&quot;&gt;:david&lt;/span&gt;).password
    assert_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/welcome&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, path
    assert_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Welcome david!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, flash[&lt;span class=&quot;symbol&quot;&gt;:notice&lt;/span&gt;]

    https!(&lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;)
    get &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/posts/all&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    assert_response &lt;span class=&quot;symbol&quot;&gt;:success&lt;/span&gt;
    assert assigns(&lt;span class=&quot;symbol&quot;&gt;:products&lt;/span&gt;)
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Capybara adds some syntactic sugar with its
&lt;code&gt;Capybara::Session#visit&lt;/code&gt; method, and produces code that reads a lot cleaner and mimics
how a user engages with the application:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test_helper&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;capybara&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;capybara_minitest_spec&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;comment&quot;&gt;# MiniTest::Spec expectations for Capybara&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;PostsTest&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActionDispatch&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;IntegrationTest&lt;/span&gt;
  fixtures &lt;span class=&quot;symbol&quot;&gt;:users&lt;/span&gt;

  test &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;login and browse site&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    visit login_path

    within find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;form#session-new&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      fill_in &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;with&lt;/span&gt;: users(&lt;span class=&quot;symbol&quot;&gt;:david&lt;/span&gt;).username
      fill_in &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;with&lt;/span&gt;: users(&lt;span class=&quot;symbol&quot;&gt;:david&lt;/span&gt;).password
      click_button &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Submit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

    current_path.must_equal welcome_path
    page.must_have_content &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Welcome david!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

    visit posts_path
    page.must_have_content &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Welcome to ReefPoints!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Jonas Nicklas, who maintains Capybara, writes how the library leads to &lt;a href=&quot;http://www.elabs.se/blog/51-simple-tricks-to-clean-up-your-capybara-tests&quot;&gt;cleaner tests and clearer intent&lt;/a&gt;. This is exactly what we
want from our tests, which not only test our code, but also
document our application&amp;#39;s behavior. A lot more could be written about
this idea, but I&amp;#39;m going to assume I&amp;#39;m preaching to the choir here and
jump into DockYard&amp;#39;s newest gem:
&lt;a href=&quot;https://rubygems.org/gems/capybara-extensions&quot;&gt;CapybaraExtensions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;CapybaraExtensions extends Capybara&amp;#39;s finders and matchers. Our goal is
to cull many of the &lt;code&gt;find&lt;/code&gt; statements from our tests and remove the
verbose CSS and
xpath locators that come along with them.&lt;/p&gt;

&lt;h2&gt;Finders&lt;/h2&gt;

&lt;h3&gt;find_&amp;lt;element&amp;gt;&lt;/h3&gt;

&lt;p&gt;The library contains helper
methods for finding elements like &lt;code&gt;form&lt;/code&gt;, &lt;code&gt;table&lt;/code&gt;, and lists, as well as
many HTML5 elements like &lt;code&gt;article&lt;/code&gt;, &lt;code&gt;aside&lt;/code&gt;, &lt;code&gt;footer&lt;/code&gt;, and &lt;code&gt;header&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the above code in which we pass a CSS selector&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;within find(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;form#session-new&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  ...
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;becomes the following:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;within form(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Login&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  ...
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this example, &amp;quot;Login&amp;quot; is text found in the form. Passing the text contained within the element we&amp;#39;re looking for better reflects what a user is thinking when she sees a form that
says &amp;quot;Login.&amp;quot;&lt;/p&gt;

&lt;p&gt;Finder methods are also aliased so that you can call &lt;code&gt;#form&lt;/code&gt;
instead of &lt;code&gt;#find_form&lt;/code&gt; (which you might expect from a finder method).
This makes for better readability with the oft-used &lt;code&gt;Capybara::Session#within&lt;/code&gt; method.&lt;/p&gt;

&lt;h3&gt;first_&amp;lt;element&amp;gt;&lt;/h3&gt;

&lt;p&gt;Each &amp;quot;find&amp;quot; method also has a corresponding &amp;quot;first&amp;quot; method. So when you
have multiple &lt;code&gt;article&lt;/code&gt; elements on a page with the text &amp;#39;Lorem ipsum,&amp;#39; you can call
&lt;code&gt;first_article(&amp;#39;Lorem ipsum&amp;#39;)&lt;/code&gt; without returning an ambiguous match in
Capybara.&lt;/p&gt;

&lt;h3&gt;&amp;lt;element&amp;gt;_number&lt;/h3&gt;

&lt;p&gt;In instances when you have lists or tables and you&amp;#39;d like to verify the
content of a specific &lt;code&gt;li&lt;/code&gt; or &lt;code&gt;tr&lt;/code&gt;, CapybaraExtensions allows
you to target the nth occurence of the element via
&lt;code&gt;#list_item_number&lt;/code&gt; and &lt;code&gt;#row_number&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So given the following HTML:&lt;/p&gt;
&lt;div class=&quot;highlight html &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;John Doe&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Jane Doe&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Juan Doe&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can find the second &lt;code&gt;li&lt;/code&gt; with:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;list_item_number(&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;) &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; &#39;Jane Doe&#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Use these methods for testing how elements are being ordered.&lt;/p&gt;

&lt;h2&gt;Matchers&lt;/h2&gt;

&lt;p&gt;CapybaraExtensions extends Capybara&amp;#39;s matchers with methods for
verifying the presence of images, the value of input fields, and the
presence of meta tags. All of these methods return a boolean.&lt;/p&gt;

&lt;h3&gt;field_values&lt;/h3&gt;

&lt;p&gt;CapybaraExtensions comes with a &lt;code&gt;#has_field_value?&lt;/code&gt; method which checks
the value of a form field. Ensuring that your records save and update
correctly should be the domain of your unit tests, however this method
can come in handy when you&amp;#39;re not persisting data to the back-end. For
example, after performing a search, you may want to ensure that the
query persists in the search field after redirect.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;within form(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Search&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  has_field_value?(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;capybara images&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;images&lt;/h3&gt;

&lt;p&gt;Asserting that text appears on the page is easy with Capybara&amp;#39;s
&lt;code&gt;#must_have_content&lt;/code&gt; method; asserting
that a particular image appears has always been a little tougher.
&lt;code&gt;#must_have_image&lt;/code&gt; takes a hash with the &lt;code&gt;src&lt;/code&gt; and/or &lt;code&gt;alt&lt;/code&gt; attributes
you&amp;#39;re looking for. You can pass a string for either of these keys, and
an instance of &lt;code&gt;Regexp&lt;/code&gt; to the &lt;code&gt;src&lt;/code&gt; attribute when you want to hone in
on a portion of the &lt;code&gt;src&lt;/code&gt; attribute without worrying about the rest of
the URL.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;page.has_image?(&lt;span class=&quot;key&quot;&gt;src&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;http://gallery.photo.net/photo/8385754-md.jpg&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
&lt;span class=&quot;key&quot;&gt;alt&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;meta_tags&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;#has_meta_tag&lt;/code&gt; checks the &lt;code&gt;head&lt;/code&gt; for meta tags. Just pass in the &lt;code&gt;name&lt;/code&gt;
and &lt;code&gt;content&lt;/code&gt; you&amp;#39;re expecting to find. We use this method quite a bit to ensure that our pages are looking good
from a search engine optimization standpoint.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;page.has_meta_tag?(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Introducing CapybaraExtensions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We hope this gem makes your tests a little more descriptive and your &lt;code&gt;test_helper.rb&lt;/code&gt; a little lighter. As always, we welcome pull requests and issues via Github. Thanks!&lt;/p&gt;

&lt;h2&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install CapybaraExtensions from &lt;a href=&quot;http://rubygems.org/gems/capybara-extensions&quot;&gt;Rubygems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow CapybaraExtensions on &lt;a href=&quot;https://github.com/dockyard/capybara-extensions&quot;&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Read up on CapybaraExtensions on
&lt;a href=&quot;http://rubydoc.info/gems/capybara-extensions/frames&quot;&gt;RubyDoc.info&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry><entry>
    <title>Design Patterns: The Command Pattern</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/11/05/design-patterns-command-pattern" />
    <id>https://dockyard.com/blog/2013/11/05/design-patterns-command-pattern</id>
    <category term="ruby" label="Ruby"/><category term="design-patterns" label="Design Patterns"/>
    <published>2013-11-05 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>Exploring design patterns and their use cases</summary>
    <content type="html">&lt;h2&gt;Let&amp;#39;s get ready for some football!&lt;/h2&gt;

&lt;p&gt;One of my favorite sports is American football; it&amp;#39;s strategic, physical,
and wild! As a fan - and once high school player - of the sport, I&amp;#39;ve gained some
valuable lessons from my experiences. For example, I&amp;#39;ve learned that &amp;quot;persistence
is key&amp;quot;, &amp;quot;giving up is for losers&amp;quot;, and that &amp;quot;water sucks, Gatorade is better.&amp;quot;&lt;/p&gt;

&lt;p&gt;While those are fine gems of wisdom, today we&amp;#39;ll be
covering one of the most overlooked teachings in football: the power
of &lt;strong&gt;Command&lt;/strong&gt; pattern.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Command&lt;/strong&gt; design pattern intends to separate and decouple an object of invocation
from the object that receives the message of invocation. We will
encapsulate all pertinent information of a method and execute the method
at a later time. Essentially, the &lt;strong&gt;Command&lt;/strong&gt; pattern gives us the ability
to queue a series of operations for a later time. Let&amp;#39;s dig in.&lt;/p&gt;

&lt;h2&gt;Put me in, Coach!&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s start by creating a &lt;code&gt;BostonNarwin&lt;/code&gt; class from which our
football players will inherit from.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# football.rb&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;BostonNarwin&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:action&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(action)
    &lt;span class=&quot;instance-variable&quot;&gt;@action&lt;/span&gt; = action
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;name&lt;/span&gt;
    &lt;span class=&quot;predefined-constant&quot;&gt;self&lt;/span&gt;.class
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, we&amp;#39;ll need some key players; let&amp;#39;s create &lt;code&gt;Quarterback&lt;/code&gt; and &lt;code&gt;Receiver&lt;/code&gt; classes.
For fun, we&amp;#39;re going to add a &lt;code&gt;TeamOwner&lt;/code&gt; class too.
All three of these classes are going to possess a method called &lt;code&gt;#execute&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each of these classes can be considered as instances of separate
&lt;strong&gt;commands&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
52
53
54
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# football.rb&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Quarterback&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;BostonNarwin&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:path&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:play&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(path, play)
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Hut! Hut! Red 19! Red 19! Hike!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@path&lt;/span&gt; = path
    &lt;span class=&quot;instance-variable&quot;&gt;@play&lt;/span&gt; = play
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;execute&lt;/span&gt;
    file = &lt;span class=&quot;constant&quot;&gt;File&lt;/span&gt;.open path, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    file.write &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;name&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;play&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    file.close
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Receiver&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;BostonNarwin&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:path&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:play&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(path, play)
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Run, run, run!!!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@path&lt;/span&gt; = path
    &lt;span class=&quot;instance-variable&quot;&gt;@play&lt;/span&gt; = play
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;execute&lt;/span&gt;
    file = &lt;span class=&quot;constant&quot;&gt;File&lt;/span&gt;.open path, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    file.write &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;name&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;play&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    file.close
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;TeamOwner&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;BostonNarwin&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:path&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:target&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(path, target)
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;We are moving the team from &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;prettify path&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;prettify target&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@path&lt;/span&gt; = path
    &lt;span class=&quot;instance-variable&quot;&gt;@target&lt;/span&gt; = target
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;execute&lt;/span&gt;
    &lt;span class=&quot;constant&quot;&gt;FileUtils&lt;/span&gt;.mv path, target
    file = &lt;span class=&quot;constant&quot;&gt;File&lt;/span&gt;.open target, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    file.write &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;name&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;: We moved from &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;prettify path&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;prettify target&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    file.close
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;prettify&lt;/span&gt;(pathname)
    (pathname.chomp &lt;span class=&quot;constant&quot;&gt;File&lt;/span&gt;.extname(pathname)).capitalize
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, let&amp;#39;s create a class that keeps track of the &lt;code&gt;Quarterback&lt;/code&gt;, &lt;code&gt;Receiver&lt;/code&gt;, and
&lt;code&gt;TeamOwner&lt;/code&gt; commands. We can use the
&lt;a href=&quot;http://reefpoints.dockyard.com/2013/10/01/design-patterns-composite-pattern.html&quot;&gt;&lt;strong&gt;Composite&lt;/strong&gt; pattern&lt;/a&gt;
to create this new class.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# football.rb&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;CompositeCommand&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;BostonNarwin&lt;/span&gt;
  attr_accessor &lt;span class=&quot;symbol&quot;&gt;:commands&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@commands&lt;/span&gt; = []
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;add_command&lt;/span&gt;(*args)
    args.each { |arg| commands &amp;lt;&amp;lt; arg }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;execute&lt;/span&gt;
    commands.each { |command| command.execute }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, we can kickoff some football commands!&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;load &#39;football.rb&#39;

quarterback = Quarterback.new(&#39;boston.txt&#39;, &#39;I&#39;m going to throw a perfect pass!&#39;)
# =&amp;gt; #&amp;lt;Quarterback:0x007ff6f5c5c148
     @action=&amp;quot;Hut! Hut! Red 19! Red 19! Hike!&amp;quot;,
     @path=&amp;quot;boston.txt&amp;quot;,
     @play=&amp;quot;I&#39;m going to throw a perfect pass!&amp;quot;&amp;gt;

receiver = Receiver.new(&#39;boston.txt&#39;, &#39;I&#39;m going to catch the ball!&#39;)
# =&amp;gt; #&amp;lt;Receiver:0x007ff6f5c949f8
     @action=&amp;quot;Run, run, run!!!&amp;quot;,
     @path=&amp;quot;boston.txt&amp;quot;,
     @play=&amp;quot;I&#39;m going to catch the ball!&amp;quot;&amp;gt;

team_owner = TeamOwner.new(&#39;boston.txt&#39;, &#39;somerville.txt&#39;)
# =&amp;gt; #&amp;lt;TeamOwner:0x007ff6f5ccd028
     @action=&amp;quot;We are moving the team from Boston to Somerville!&amp;quot;,
     @path=&amp;quot;boston.txt&amp;quot;,
     @target=&amp;quot;somerville.txt&amp;quot;&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Great! Now we&amp;#39;ll create an instance of the &lt;code&gt;CompositeCommand&lt;/code&gt;, add
each sub-command with &lt;code&gt;#add_command&lt;/code&gt;, and then execute each command
with &lt;code&gt;#execute&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;command = CompositeCommand.new
# =&amp;gt; #&amp;lt;CompositeCommand:0x007ff6f5b82948 @commands=[]&amp;gt;

command.add_command quarterback, receiver, team_owner
# =&amp;gt; [#&amp;lt;Quarterback:0x007ff6f5c5c148
     @action=&amp;quot;Hut! Hut! Red 19! Red 19! Hike!&amp;quot;,
     @path=&amp;quot;boston.txt&amp;quot;,
     @play=&amp;quot;I&#39;m going to throw a perfect pass!&amp;quot;&amp;gt;,
     #&amp;lt;Receiver:0x007ff6f5c949f8
     @action=&amp;quot;Run, run, run!!!&amp;quot;,
     @path=&amp;quot;boston.txt&amp;quot;,
     @play=&amp;quot;I&#39;m going to catch the ball!&amp;quot;&amp;gt;,
     #&amp;lt;TeamOwner:0x007ff6f5ccd028
     @action=&amp;quot;We are moving the team from Boston to Somerville!&amp;quot;,
     @path=&amp;quot;boston.txt&amp;quot;,
     @target=&amp;quot;somerville.txt&amp;quot;&amp;gt;]

command.execute
# ...  Omitted for brevity ...

exit
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Finally, let&amp;#39;s list out the files in our current directory and view the contents
of our recently created text file.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;$ ls
# =&amp;gt; football.rb   somerville.txt

$ less somerville.txt
# =&amp;gt; Quarterback: I&#39;m going to throw a perfect pass!
     Receiver: I&#39;m going to catch the ball!
     TeamOwner: We moved from Boston to Somerville!
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Wow! The &lt;strong&gt;Command&lt;/strong&gt; pattern in action!&lt;/p&gt;

&lt;h2&gt;Discussion&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Command&lt;/strong&gt; pattern suggests that we create objects that perform
specific tasks and actions. For our example, the &lt;code&gt;Quarterback&lt;/code&gt; object
created a file, the &lt;code&gt;Receiver&lt;/code&gt; appended to the file, and the &lt;code&gt;TeamOwner&lt;/code&gt;
object moved it. Each of the command objects completed their action
through &lt;code&gt;CompositeCommand#execute&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Having one object, an instance of &lt;code&gt;CompositeCommand&lt;/code&gt;, that executes all
stored commands presents us with solutions ranging from simple file
manipulation to user triggered interaction. The &lt;strong&gt;Command&lt;/strong&gt; pattern
also allows us to &amp;quot;store&amp;quot; and &amp;quot;remember&amp;quot; commands prior to and after
execution.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed our example and go Boston Narwins!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Buffers, Windows, Tabs... Oh My! Part 1: Vim Buffers</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/10/22/vim-buffers" />
    <id>https://dockyard.com/blog/2013/10/22/vim-buffers</id>
    <category term="vim" label="Vim"/><category term="workflow" label="Workflow"/>
    <published>2013-10-22 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>A painless tutorial on Vim buffers</summary>
    <content type="html">&lt;p&gt;First off, &lt;a href=&quot;http://boston.redsox.mlb.com&quot;&gt;GO SOX&lt;/a&gt;!!!11&lt;/p&gt;

&lt;p&gt;Now that I&amp;#39;ve reinforced my allegiance to America&amp;#39;s favorite baseball team, let&amp;#39;s
talk about Vim. In this series of posts, we&amp;#39;ll explore buffers,
windows, and tabs.&lt;/p&gt;

&lt;p&gt;Today, our topic will be &lt;em&gt;buffers&lt;/em&gt;, editable files that are
available in-memory.&lt;/p&gt;

&lt;p&gt;When you first open a file through a Vim session, you are creating and working
in a buffer, typically through a window. For the sake of today&amp;#39;s discussion,
we will consider working with multiple buffers through only one window, our
viewport of the working buffer.&lt;/p&gt;

&lt;h3&gt;Let&amp;#39;s open a buffer&lt;/h3&gt;

&lt;p&gt;We&amp;#39;re going to setup an easy exercise for today&amp;#39;s post. If you don&amp;#39;t want to
follow along, feel free to try the exercise in your own project.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s create a dummy directory and some of text files:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;mkdir dummy &amp;amp;&amp;amp; cd dummy
echo &#39;The Red Sox rule!&#39; &amp;gt; redsox.txt &amp;amp;&amp;amp; echo &#39;Cardinals drool!&#39; &amp;gt; cardinals.txt
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, open up the &lt;code&gt;redsox.txt&lt;/code&gt; file.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;vim redsox.txt      # =&amp;gt; The Red Sox rule!
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Congratulations, you&amp;#39;re already using buffers!&lt;/p&gt;

&lt;h3&gt;Buffer indicators&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s open the &lt;code&gt;cardinals.txt&lt;/code&gt; file in a &lt;em&gt;hidden&lt;/em&gt; buffer. We can accomplish
this through the current &lt;code&gt;redsox.txt&lt;/code&gt; buffer by using &lt;code&gt;:badd&lt;/code&gt; or &lt;code&gt;:bad&lt;/code&gt;. Next, we&amp;#39;ll
list out all buffers, hidden or active, with &lt;code&gt;:ls&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;# Inside the current buffer, get into Vim&#39;s command mode and use the command `:badd`.
# List all buffers with `:ls`.

:badd candinals.txt     # &#39;badd&#39; =&amp;gt; &#39;Buffer ADD&#39;
                        # You can also use `:bad`
:ls
  ### =&amp;gt;   1    %a   &amp;quot;redsox.txt&amp;quot;              line 1
           2         &amp;quot;cardinals.txt&amp;quot;           line 1
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;:ls&lt;/code&gt; command returns information about each buffer: the unique buffer
number, buffer indicators, file name, and the line number of your current
position within the file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buffer number: A unique number to identify individual buffers.&lt;/li&gt;
&lt;li&gt;Buffer indicators:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%&lt;/code&gt;: buffer in the current window&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#&lt;/code&gt;: alternate buffer, which can be accessed by &lt;code&gt;CTRL-6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt;: active buffer, loaded and visible&lt;/li&gt;
&lt;li&gt;&lt;code&gt;h&lt;/code&gt;: hidden buffer, loaded but not visible&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;: a buffer that cannot be modified, &lt;code&gt;modifiable&lt;/code&gt; off&lt;/li&gt;
&lt;li&gt;&lt;code&gt;=&lt;/code&gt;: a buffer that is readonly&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+&lt;/code&gt;: a buffer that has been successfully modified&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;: a buffer with read errors&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&lt;/code&gt;: if there is no buffer indicator, it signifies a buffer that has not been
loaded yet&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Buffer name: The name of the file.&lt;/li&gt;
&lt;li&gt;Buffer line number: The current line number that the cursor is on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Working with multiple buffers&lt;/h3&gt;

&lt;p&gt;As we can see, our &lt;code&gt;cardinals.txt&lt;/code&gt; has yet to be loaded. Let&amp;#39;s open it into
our window and view our current buffers.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:e cardinals.txt   # =&amp;gt; Cardinals drool!

:ls
  ### =&amp;gt;   1    #    &amp;quot;redsox.txt&amp;quot;              line 1
           2    %a   &amp;quot;cardinals.txt&amp;quot;           line 1
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Nice! We can see that our &lt;code&gt;redsox.txt&lt;/code&gt; file is our alternate buffer. Let&amp;#39;s switch
to the &lt;code&gt;redsox.txt&lt;/code&gt; by hitting &lt;code&gt;CTRL-6&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we&amp;#39;ll create a new text file, &lt;code&gt;worldseries.txt&lt;/code&gt;, write &lt;code&gt;World Series!&lt;/code&gt; inside that file,
and check out our list of buffers.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;:e worldseries.txt   # Write &amp;quot;World Series!&amp;quot; inside the file and save it.
:ls
  ### =&amp;gt;   1    #    &amp;quot;redsox.txt&amp;quot;              line 1
           2         &amp;quot;cardinals.txt&amp;quot;           line 1
           3    %a   &amp;quot;worldseries.txt&amp;quot;         line 1
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Our alternate buffer is the &lt;code&gt;redsox.txt&lt;/code&gt; file. Remember, if we want to quickly
switch to the alternate buffer, we can use &lt;code&gt;CTRL-6&lt;/code&gt;. What if we want to open the
&lt;code&gt;cardinals.txt&lt;/code&gt; into our current window?&lt;/p&gt;

&lt;p&gt;Well, we have a couple of options. From the &lt;code&gt;worldseries.txt&lt;/code&gt; file, we can use the
following vim commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:bp&lt;/code&gt; :  Switch to the previous buffer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:b2&lt;/code&gt; :  Switch to buffer number 2

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:b&lt;/code&gt; : Takes a buffer number as an argument&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go ahead and give it a try.&lt;/p&gt;

&lt;p&gt;Here are some other pertinent buffer commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:bn&lt;/code&gt; : Switch to the next buffer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:ball&lt;/code&gt; : Open all buffers into windows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:brew&lt;/code&gt; : Go back to the first buffer in the list - &amp;quot;Buffer REWind&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:bd&lt;/code&gt; : Delete the buffer - also takes buffer numbers as arguments

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:bd 1 2 3&lt;/code&gt; : Will remove buffer numbers 1, 2, and 3&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Note&lt;/em&gt;: &lt;code&gt;:q&lt;/code&gt; is not the same as &lt;code&gt;:bd&lt;/code&gt;... try it and verify with &lt;code&gt;:ls&lt;/code&gt;!&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;So what good are buffers?&lt;/h3&gt;

&lt;p&gt;To be honest, I just realized the power of buffers about a month ago.
Previously, thanks to a large monitor, I would have multtple windows
- as many as 6-8 - open during one Vim session.
Multiple windows are great, however, if I really needed to focus on a few
files, I&amp;#39;d have to close each insignificant file window.&lt;/p&gt;

&lt;p&gt;Nowadays, my workflow comprises of two or three windows, with multiple buffers in the background.
This has allowed me to rapidly move between files that I actively open and edit.&lt;/p&gt;

&lt;h3&gt;Remapping buffer commands&lt;/h3&gt;

&lt;p&gt;Here are some key remappings that speed up buffer movement:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;quot; ~/.vimrc (or wherever else you keep your .vimrc)

&amp;quot; Move to the previous buffer with &amp;quot;gp&amp;quot;
nnoremap gp :bp&amp;lt;CR&amp;gt;

&amp;quot; Move to the next buffer with &amp;quot;gn&amp;quot;
nnoremap gn :bn&amp;lt;CR&amp;gt;

&amp;quot; List all possible buffers with &amp;quot;gl&amp;quot;
nnoremap gl :ls&amp;lt;CR&amp;gt;

&amp;quot; List all possible buffers with &amp;quot;gb&amp;quot; and accept a new buffer argument [1]
nnoremap gb :ls&amp;lt;CR&amp;gt;:b
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Remapping &lt;code&gt;gp&lt;/code&gt; will remove the Vim default functionality of &lt;code&gt;gp&lt;/code&gt;.
Use &lt;code&gt;:h gp&lt;/code&gt; to read more about it.&lt;/p&gt;

&lt;p&gt;Hope that provides some insight into the capabilities of Vim buffers!
If there is anything you&amp;#39;d like to add, please feel free and
comment in the discussion area. Thanks!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[1] Special thanks to &lt;a href=&quot;http://www.reddit.com/r/vim/comments/1p2a62/a_painless_tutorial_on_vim_buffers/ccxzq7e&quot;&gt;romainl&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry><entry>
    <title>Namespaced Pages</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/10/06/namespaced-pages" />
    <id>https://dockyard.com/blog/2013/10/06/namespaced-pages</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2013-10-06 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>New functionality for the gem</summary>
    <content type="html">&lt;h2&gt;Simple Namespacing&lt;/h2&gt;

&lt;p&gt;We&amp;#39;ve been using our &lt;a href=&quot;https://github.com/dockyard/pages&quot;&gt;Pages&lt;/a&gt; gem in
nearly all of our projects for over a year now. Its been great but could
only support pages on the root. I just released &lt;code&gt;0.2.0&lt;/code&gt; of the gem that
now supports namespacing:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;namespace &lt;span class=&quot;symbol&quot;&gt;:work&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  pages &lt;span class=&quot;symbol&quot;&gt;:client_1&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:client_2&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This will give you the routes of &lt;code&gt;/work/client_1&lt;/code&gt; and &lt;code&gt;/work/client_2&lt;/code&gt;.
Your views will go into &lt;code&gt;app/views/work/pages&lt;/code&gt;. For more details see the
&lt;a href=&quot;https://github.com/dockyard/pages#namespacing&quot;&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In a future release of &lt;code&gt;Pages&lt;/code&gt; we plan on adding support automatic
pages. For example, you will no longer need to declare the pages in your
&lt;code&gt;config/routes.rb&lt;/code&gt; file. As long as the templates exist in the
&lt;code&gt;app/views/pages&lt;/code&gt; directory the route will happen automatically. In
addition we will also add support for pages nested under different
namespaces, or accessible from certain authentication state. All in the
name of serving up static page goodness!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Design Patterns: The Composite Pattern</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/10/01/design-patterns-composite-pattern" />
    <id>https://dockyard.com/blog/2013/10/01/design-patterns-composite-pattern</id>
    <category term="design-patterns" label="Design Patterns"/><category term="ruby" label="Ruby"/>
    <published>2013-10-01 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>Exploring design patterns and their use cases</summary>
    <content type="html">&lt;h2&gt;Coffee Coffee&lt;/h2&gt;

&lt;p&gt;If you&amp;#39;re anything like me, you&amp;#39;ll agree that every morning needs to start
out with a cup of coffee. And, if you&amp;#39;re anything like me, you&amp;#39;ll have
at least three different coffee making apparatuses. And, if you&amp;#39;re
anything like me... you&amp;#39;ll soon realize you may have an addiction.&lt;/p&gt;

&lt;p&gt;Joke aside, each coffee contraption requires a specific procedure
to be completed in order to brew a cup of joe; each having multiple parts,
taking differing amounts of time, requiring various numbers of steps, etc.&lt;/p&gt;

&lt;p&gt;Our coffee making process can be described by a basic example
of the &lt;em&gt;Composite&lt;/em&gt; method pattern.&lt;/p&gt;

&lt;h2&gt;The Best Part of Waking Up is a Composite Pattern in Your Cup&lt;/h2&gt;

&lt;p&gt;We can start by thinking of each coffee maker and coffee related task as a &lt;em&gt;subclass&lt;/em&gt; of
our &lt;code&gt;CoffeeRoutine&lt;/code&gt;. &lt;code&gt;CoffeeRoutine&lt;/code&gt; will be known as the &lt;em&gt;component&lt;/em&gt;, the base
class or interface that possesses the commonalities of simple and complex
objects. &lt;code&gt;CoffeeRoutine#time&lt;/code&gt; is the common trait among all
coffee related classes.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;CoffeeRoutine&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:task&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(task)
    &lt;span class=&quot;instance-variable&quot;&gt;@task&lt;/span&gt; = task
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;time&lt;/span&gt;
    &lt;span class=&quot;float&quot;&gt;0.0&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, we&amp;#39;ll create a couple of &lt;em&gt;leaf&lt;/em&gt; classes, which represent
indivisble portions of our pattern. Here are a couple of &lt;em&gt;leaf&lt;/em&gt; classes
that come to mind: &lt;code&gt;GrindCoffee&lt;/code&gt; and &lt;code&gt;BoilWater&lt;/code&gt;. These &lt;em&gt;leaf&lt;/em&gt; classes are
our most basic steps to making coffee.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;GrindCoffee&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;CoffeeRoutine&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Grinding some coffee!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;time&lt;/span&gt;
    &lt;span class=&quot;float&quot;&gt;0.5&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;BoilWater&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;CoffeeRoutine&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Boiling some water!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;time&lt;/span&gt;
    &lt;span class=&quot;float&quot;&gt;4.0&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;AddCoffee&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;CoffeeRoutine&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Adding in the coffee!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;time&lt;/span&gt;
    &lt;span class=&quot;float&quot;&gt;1.0&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;g = GrindCoffee.new

g.task    # =&amp;gt; &#39;Grinding some coffee!&#39;
g.time    # =&amp;gt; 0.5
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, we can get to the namesake of the pattern: the &lt;em&gt;composite&lt;/em&gt; class. A
&lt;em&gt;composite&lt;/em&gt; class is a &lt;em&gt;component&lt;/em&gt; that also contain
&lt;em&gt;subcomponents&lt;/em&gt;. &lt;em&gt;Composite&lt;/em&gt; classes can be made up of smaller
&lt;em&gt;composite&lt;/em&gt; classes or &lt;em&gt;leaf&lt;/em&gt; classes.&lt;/p&gt;

&lt;p&gt;Our various coffee making apparatuses can be thought of as &lt;em&gt;composites&lt;/em&gt;.
Let&amp;#39;s check out the &lt;code&gt;FrenchPress&lt;/code&gt; class:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;FrenchPress&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;CoffeeRoutine&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:task&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:steps&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(task)
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Using the French press to make coffee&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@steps&lt;/span&gt; = []
    add_step &lt;span class=&quot;constant&quot;&gt;BoilWater&lt;/span&gt;.new
    add_step &lt;span class=&quot;constant&quot;&gt;GrindCoffee&lt;/span&gt;.new
    add_step &lt;span class=&quot;constant&quot;&gt;AddCoffee&lt;/span&gt;.new
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;add_step&lt;/span&gt;(step)
    steps &amp;lt;&amp;lt; step
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;remove_step&lt;/span&gt;(step)
    steps.delete step
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;time_required&lt;/span&gt;
    total_time = &lt;span class=&quot;float&quot;&gt;0.0&lt;/span&gt;
    steps.each { |step| total_time += step.time }
    total_time
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;However, we can simplify the &lt;code&gt;FrenchPress&lt;/code&gt; class by pulling out the
&lt;em&gt;composite&lt;/em&gt; functionality into its own class.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;CompositeTasks&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;CoffeeRoutine&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:task&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:steps&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(task)
    &lt;span class=&quot;instance-variable&quot;&gt;@steps&lt;/span&gt; = []
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;add_step&lt;/span&gt;(step)
    steps &amp;lt;&amp;lt; step
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;remove_step&lt;/span&gt;(step)
    steps.delete step
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;time_required&lt;/span&gt;
    total_time = &lt;span class=&quot;float&quot;&gt;0.0&lt;/span&gt;
    steps.each { |step| total_time += step.time }
    total_time
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we can create &lt;em&gt;composite&lt;/em&gt; coffee makers easily... They&amp;#39;ll look
something like this:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;FrenchPress&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;CompositeTasks&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Using the FrenchPress to make coffee!!!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    add_step &lt;span class=&quot;constant&quot;&gt;GrindCoffee&lt;/span&gt;.new
    add_step &lt;span class=&quot;constant&quot;&gt;BoilWater&lt;/span&gt;.new
    add_step &lt;span class=&quot;constant&quot;&gt;AddCoffee&lt;/span&gt;.new
    &lt;span class=&quot;comment&quot;&gt;# ... Omitted actual steps to make coffee from a French press ...&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;# ... Imagine PressPlunger class has been defined already ...&lt;/span&gt;
    add_step &lt;span class=&quot;constant&quot;&gt;PressPlunger&lt;/span&gt;.new
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;DripMaker&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;CompositeTasks&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Using the DripMaker to make coffee!!!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    add_step &lt;span class=&quot;constant&quot;&gt;GrindCoffee&lt;/span&gt;.new
    add_step &lt;span class=&quot;constant&quot;&gt;BoilWater&lt;/span&gt;
    add_step &lt;span class=&quot;constant&quot;&gt;AddCoffee&lt;/span&gt;.new
    &lt;span class=&quot;comment&quot;&gt;# ... Imagine PressStartButton class has been defined already ...&lt;/span&gt;
    add_step &lt;span class=&quot;constant&quot;&gt;PressStartButton&lt;/span&gt;.new
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Swell... now we can call the &lt;code&gt;FrenchPress&lt;/code&gt; and &lt;code&gt;DripMaker&lt;/code&gt; coffee makers.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;frenchpress = FrenchPress.new

# =&amp;gt; #&amp;lt;FrenchPress:0x007f88fcf46410
       @task=&amp;quot;Using the FrenchPress to make coffee!!!&amp;quot;,
       @steps=
         [#&amp;lt;GrindCoffee:0x007f88fcf46370 @step=&amp;quot;Grinding some coffee!&amp;quot;&amp;gt;,
         #&amp;lt;BoilWater:0x007f88fcf46320 @step=&amp;quot;Boiling some water!&amp;quot;&amp;gt;]&amp;gt;
         #&amp;lt;AddCoffee:0x007f88fcf46329 @step=&amp;quot;Adding in the coffee!&amp;quot;&amp;gt;]&amp;gt;
         #&amp;lt;PressPlunger:0x007f88fcf46098 @step=&amp;quot;Pressing the plunger down!&amp;quot;&amp;gt;]&amp;gt;

dripmaker = DripMaker.new

# =&amp;gt; #&amp;lt;DripMaker:0x137t88fcf57109
       @task=&amp;quot;Using the DripMaker to make coffee!!!&amp;quot;,
       @steps=
         [#&amp;lt;GrindCoffee:0x007f88fcf46370 @step=&amp;quot;Grinding some coffee!&amp;quot;&amp;gt;,
         #&amp;lt;BoilWater:0x007f88fcf52520 @step=&amp;quot;Boiling some water!&amp;quot;&amp;gt;]&amp;gt;
         #&amp;lt;AddCoffee:0x007f88fcf46123 @step=&amp;quot;Adding in the coffee!&amp;quot;&amp;gt;]&amp;gt;
         #&amp;lt;PressStartButton:0x007f88fcf46432 @step=&amp;quot;Pushing the start button!&amp;quot;&amp;gt;]&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we can also check the time required for each coffee maker.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;frenchpress.time_required # =&amp;gt; 12.4
dripmaker.time_required   # =&amp;gt; 8.5
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Discussion&lt;/h2&gt;

&lt;p&gt;Implementing the &lt;em&gt;Composite&lt;/em&gt; pattern is pretty simple.&lt;/p&gt;

&lt;p&gt;We create a &lt;em&gt;component&lt;/em&gt; class that ties the numerous simple and
complex characteristics together. In our example, &lt;code&gt;CoffeeRoutine&lt;/code&gt;
defines an elementary method &lt;code&gt;#time&lt;/code&gt; and each child class implements
its own amount.&lt;/p&gt;

&lt;p&gt;Next, we create &lt;em&gt;leaf&lt;/em&gt; classes, &lt;code&gt;AddCoffee&lt;/code&gt;, &lt;code&gt;BoilWater&lt;/code&gt;, and &lt;code&gt;GrindCoffee&lt;/code&gt;,
that share the same characteristics with one another. Remember that it&amp;#39;s the nature
of &lt;em&gt;leaf&lt;/em&gt; classes to be simple. If you happen across a &lt;em&gt;leaf&lt;/em&gt; class that
could be broken up, it might potentially be a &lt;em&gt;composite&lt;/em&gt; class in disguise.
Break up those actions into individual &lt;em&gt;leaf&lt;/em&gt; classes and turn the original class
into a &lt;em&gt;composite&lt;/em&gt;. All of our &lt;em&gt;leaf&lt;/em&gt; classes had a &lt;code&gt;#time&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;composite&lt;/em&gt; class handles all the subtasks, essentially using the child classes
at its will. We can see that our two &lt;em&gt;composite&lt;/em&gt; classes and their methods, &lt;code&gt;FrenchPress#time_required&lt;/code&gt;
and &lt;code&gt;DripMaker#time_required&lt;/code&gt;. manipulate the method &lt;code&gt;#time&lt;/code&gt; from the &lt;em&gt;leaf&lt;/em&gt; classes.
Ultimately, our coffee makers are able to treat each step,
&lt;code&gt;GrindCoffee&lt;/code&gt;, &lt;code&gt;BoilWater&lt;/code&gt; and &lt;code&gt;AddCoffee&lt;/code&gt; uniformly.&lt;/p&gt;

&lt;p&gt;Hope this helps you with your morning routine!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Vim: Moving Lines Ain&#39;t Hard</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/09/26/vim-moving-lines-aint-hard" />
    <id>https://dockyard.com/blog/2013/09/26/vim-moving-lines-aint-hard</id>
    <category term="workflow" label="Workflow"/><category term="vim" label="Vim"/>
    <published>2013-09-26 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>Quick ways to move lines</summary>
    <content type="html">&lt;p&gt;In the last post, we briefly discussed the power of the
&lt;a href=&quot;http://reefpoints.dockyard.com/2013/09/11/vim-staying-on-home-row-via-map.html&quot;&gt;&lt;em&gt;map&lt;/em&gt; command&lt;/a&gt;.
In today&amp;#39;s post, we&amp;#39;re going to use &lt;em&gt;map&lt;/em&gt; again in order to move
lines and blocks around.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s use an example:
Our goal is to move the &lt;em&gt;first line&lt;/em&gt; to its proper location. From this:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;--- second line ---
--- third line ---
--- first line ---
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To this:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;--- first line ---
--- second line ---
--- third line ---
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Delete, Then Paste&lt;/h2&gt;

&lt;p&gt;Here is one of the most common ways, it ain&amp;#39;t pretty but it gets the job done.
We&amp;#39;ll delete the desired line and paste it to the target location.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;--- second line ---
--- third line ---
--- first line ---

# Delete the &amp;quot;first line&amp;quot;, move to the &amp;quot;second line&amp;quot;, and paste the registered
# &amp;quot;first line&amp;quot; above the &amp;quot;second line&amp;quot;.
#
# :3 --&amp;gt; &amp;lt;ENTER&amp;gt; --&amp;gt; dd --&amp;gt; j --&amp;gt; P
#
# or...
#
# :3d --&amp;gt; &amp;lt;ENTER&amp;gt; --&amp;gt; :2P --&amp;gt; &amp;lt;ENTER&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;I Like the Way You Move&lt;/h2&gt;

&lt;p&gt;The second way, use the &lt;em&gt;move&lt;/em&gt; command with &lt;code&gt;:m&lt;/code&gt;. I like this method a lot, as it
requires fewer keystrokes. It does require line numbers though. When using
absolute line numbers, the destination will be below the line number you specify,
so use &lt;code&gt;:m0&lt;/code&gt; to move to the top of the file.
Try using
&lt;a href=&quot;http://jeffkreeftmeijer.com/2013/vims-new-hybrid-line-number-mode/&quot;&gt;hybrid mode&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;--- second line ---
--- third line ---
--- first line ---

# Move your cursor on the &amp;quot;first line&amp;quot; (the third line), use the *move* command and
# pass your desired line number as an argument. Hit enter.
#
# :3 --&amp;gt; &amp;lt;ENTER&amp;gt; --&amp;gt; :m0 --&amp;gt; &amp;lt;ENTER&amp;gt;
#
# or...
#
# :3m0 --&amp;gt; &amp;lt;ENTER&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Lazy Moving&lt;/h2&gt;

&lt;p&gt;Now getting to the &lt;em&gt;map&lt;/em&gt; command, I&amp;#39;ve found this pretty handy when
I need to move a line or block of lines a couple of lines upward or downward.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;quot; In your ~/.vimrc
&amp;quot;
&amp;quot; Normal mode
nnoremap &amp;lt;C-j&amp;gt; :m .+1&amp;lt;CR&amp;gt;==
nnoremap &amp;lt;C-k&amp;gt; :m .-2&amp;lt;CR&amp;gt;==

&amp;quot; Insert mode
inoremap &amp;lt;C-j&amp;gt; &amp;lt;ESC&amp;gt;:m .+1&amp;lt;CR&amp;gt;==gi
inoremap &amp;lt;C-k&amp;gt; &amp;lt;ESC&amp;gt;:m .-2&amp;lt;CR&amp;gt;==gi

&amp;quot; Visual mode
vnoremap &amp;lt;C-j&amp;gt; :m &#39;&amp;gt;+1&amp;lt;CR&amp;gt;gv=gv
vnoremap &amp;lt;C-k&amp;gt; :m &#39;&amp;lt;-2&amp;lt;CR&amp;gt;gv=gv
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now you can move lines by holding &lt;em&gt;CTRL&lt;/em&gt; and &lt;em&gt;j&lt;/em&gt; (for up a line) or
&lt;em&gt;k&lt;/em&gt; (for down a line).&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;--- second line ---
--- third line ---
--- first line ---

# Move to the &amp;quot;first line&amp;quot;, hold &amp;lt;CTRL&amp;gt; and move up twice.
#
# :3 --&amp;gt; &amp;lt;ENTER&amp;gt; --&amp;gt; &amp;lt;CTRL&amp;gt; + kk
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now let&amp;#39;s move a block of lines:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;--- fourth line ---
--- fifth line ---
--- first line ---
--- second line ---
--- third line ---

# Move to the &amp;quot;first line&amp;quot;.
# Select the &amp;quot;first line&amp;quot;, &amp;quot;second line&amp;quot;, and the &amp;quot;third line&amp;quot; with Visual mode.
# Hit CTRL and move upwards twice.
#
# :3 -- &amp;lt;ENTER&amp;gt; --&amp;gt; &amp;lt;SHIFT&amp;gt; + V --&amp;gt; jj --&amp;gt; &amp;lt;CTRL&amp;gt; + kk
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Other Ways&lt;/h2&gt;

&lt;p&gt;There are plenty of other tricks that move around lines in Vim. The preceding
examples were just a few that I employ everyday. If you&amp;#39;ve got something cool to
share, please let me know!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Vim: Staying on Home Row via Map</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/09/11/vim-staying-on-home-row-via-map" />
    <id>https://dockyard.com/blog/2013/09/11/vim-staying-on-home-row-via-map</id>
    <category term="vim" label="Vim"/><category term="workflow" label="Workflow"/>
    <published>2013-09-11 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>Map commands for quick escapes and saves</summary>
    <content type="html">&lt;p&gt;Here at DockYard, the majority of us are using Vim. I don&amp;#39;t want to
write about the benefits of using this sweet editor, as that would take too long,
but instead, I&amp;#39;d like to share a couple of my favorite mappings for
escaping and saving files.&lt;/p&gt;

&lt;h2&gt;Vanilla Vim: Escaping and Saving&lt;/h2&gt;

&lt;p&gt;Escaping out to &lt;em&gt;Normal&lt;/em&gt; mode from the other modes in Vim is straightforward:
simply hit the &lt;code&gt;Esc&lt;/code&gt; key.
Saving files is accomplished by, from &lt;code&gt;Normal&lt;/code&gt; mode, pressing &lt;code&gt;:w&lt;/code&gt; and then &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;So... What&amp;#39;s the Problem?&lt;/h2&gt;

&lt;p&gt;During a session, especially when I&amp;#39;m writing large pieces of text,
I&amp;#39;d find myself in a repetitive rut:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I just typed out a couple of sentences and want to save my progress&lt;/li&gt;
&lt;li&gt;I&amp;#39;d remove my left hand from home row to hit the &lt;code&gt;Esc&lt;/code&gt; key&lt;/li&gt;
&lt;li&gt;Saving the file required me, once again to leave home row, to hit &lt;code&gt;:w&lt;/code&gt;
and then the &lt;code&gt;Enter&lt;/code&gt; or the &lt;code&gt;Return&lt;/code&gt; key&lt;/li&gt;
&lt;li&gt;To continue on, I&amp;#39;d press &lt;code&gt;i&lt;/code&gt; and type along&lt;/li&gt;
&lt;li&gt;Repeat, repeat, repeat...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See where I&amp;#39;m getting at?&lt;/p&gt;

&lt;h2&gt;Let&amp;#39;s Talk About Map&lt;/h2&gt;

&lt;p&gt;Before we review and
&lt;a href=&quot;http://www.flickr.com/search/?q=pasta&quot;&gt;copy-pasta&lt;/a&gt;
the portion of my &lt;code&gt;.vimrc&lt;/code&gt;, let&amp;#39;s briefly go over the very basics of the
pertinent map commands.
You can find the entire &lt;a href=&quot;http://vimdoc.sourceforge.net/htmldoc/map.html&quot;&gt;map documentation here&lt;/a&gt;
or by typing &lt;code&gt;:help map&lt;/code&gt; within a Vim session.&lt;/p&gt;

&lt;p&gt;Protip: To open help texts into a full buffer, &lt;code&gt;:h map | only&lt;/code&gt; or to open them in a separate tab &lt;code&gt;:tab h map&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Recursive Map&lt;/h3&gt;

&lt;p&gt;First, we&amp;#39;re going to talk about &lt;em&gt;recursive&lt;/em&gt; map commands. A &lt;em&gt;recursive&lt;/em&gt;
command will transform one result to another result, if there is another
binding to that key. An example can be found at the &lt;code&gt;.vimrc&lt;/code&gt; below.&lt;/p&gt;

&lt;p&gt;Here are the basic &lt;em&gt;recursive&lt;/em&gt; map commands.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;map&lt;/code&gt;  - command to transform the operation of typed keys within &lt;em&gt;ALL&lt;/em&gt; modes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can prepend the first letter of the desired mode to &lt;code&gt;map&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nmap&lt;/code&gt; - transform the operation of typed keys within &lt;em&gt;Normal&lt;/em&gt;
mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;imap&lt;/code&gt; - transform the operations of typed keys within
&lt;em&gt;Insert&lt;/em&gt; mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vmap&lt;/code&gt; - transform the operations of typed keys within
&lt;em&gt;Visual&lt;/em&gt; and &lt;em&gt;Select&lt;/em&gt; mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if I had this within my &lt;code&gt;.vimrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;quot; ~/.vimrc
&amp;quot;
&amp;quot; Note: double quotes signifies comments

nmap 0 gg
imap n N

&amp;quot; Time for a little recursive map
imap d D
imap D wat
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Since &lt;code&gt;0&lt;/code&gt; is mapped to &lt;code&gt;gg&lt;/code&gt; within &lt;em&gt;Normal&lt;/em&gt; mode, I&amp;#39;ll be sent to the
top of the file by pressing &lt;code&gt;0&lt;/code&gt;.
Moreover, while in &lt;em&gt;Insert&lt;/em&gt; mode, every character &lt;code&gt;n&lt;/code&gt; that I type will turn into &lt;code&gt;N&lt;/code&gt;.
Lastly, because of the recursive mapping, typing &lt;code&gt;d&lt;/code&gt; in &lt;em&gt;Insert&lt;/em&gt; mode
will return &lt;code&gt;wat&lt;/code&gt;. You can think of it as something like: &lt;code&gt;d&lt;/code&gt; =&amp;gt; &lt;code&gt;D&lt;/code&gt; =&amp;gt;
&lt;code&gt;wat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thankfully, there&amp;#39;s a &lt;em&gt;non-recursive&lt;/em&gt; map.&lt;/p&gt;

&lt;h3&gt;Non-recursive Map&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Non-recursive&lt;/em&gt; map commands are signified by adding &lt;code&gt;nore&lt;/code&gt; after the
 mode modifier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nnoremap&lt;/code&gt; - non-recursive map for &lt;em&gt;Normal&lt;/em&gt; mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inoremap&lt;/code&gt; - non-recursive map for &lt;em&gt;Insert&lt;/em&gt; mode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vnoremap&lt;/code&gt; - non-recursive map for &lt;em&gt;Visual&lt;/em&gt; and &lt;em&gt;Select&lt;/em&gt; mode&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;quot; ~/.vimrc

inoremap c C
inoremap C nope
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, in &lt;em&gt;Insert&lt;/em&gt; mode, if we type &lt;code&gt;c&lt;/code&gt;, we will return &lt;code&gt;C&lt;/code&gt;; the transformation of
&lt;code&gt;c&lt;/code&gt; to &lt;code&gt;nope&lt;/code&gt; will not occur.&lt;/p&gt;

&lt;h2&gt;Enter the .vimrc&lt;/h2&gt;

&lt;p&gt;Now that we got the basics out of the way, here is an example of my
&lt;code&gt;.vimrc&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;quot; ~/.vimrc
&amp;quot; *** The Two Hand system ***
&amp;quot;
&amp;quot; &amp;lt;Cr&amp;gt; signifies the &amp;quot;return&amp;quot; key

inoremap ;a &amp;lt;Esc&amp;gt;
inoremap ;d &amp;lt;Esc&amp;gt;:update&amp;lt;Cr&amp;gt;
inoremap ;f &amp;lt;C-O&amp;gt;:update&amp;lt;Cr&amp;gt;
nnoremap ;f :update&amp;lt;CR&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I&amp;#39;m using &lt;code&gt;:update&lt;/code&gt; here, which is &amp;quot;like &lt;code&gt;:write&lt;/code&gt;, but only write when the buffer has been
modified.&amp;quot;&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s go over these mappings.&lt;/p&gt;

&lt;p&gt;The first one, &lt;code&gt;inoremap ;a &amp;lt;Esc&amp;gt;&lt;/code&gt; maps the &lt;em&gt;semi-colon&lt;/em&gt; and &lt;em&gt;a&lt;/em&gt; key
together when in &lt;em&gt;Insert&lt;/em&gt; mode. By pressing &lt;code&gt;;&lt;/code&gt; and then &lt;code&gt;a&lt;/code&gt; immediately afterwards, we mimic
the functionality of the &lt;em&gt;Escape&lt;/em&gt; key.&lt;/p&gt;

&lt;p&gt;The second map, &lt;code&gt;inoremap ;d &amp;lt;Esc&amp;gt;:update&amp;lt;Cr&amp;gt;&lt;/code&gt; maps the &lt;em&gt;semi-colon&lt;/em&gt; and the &lt;em&gt;d&lt;/em&gt; key.
Pressing &lt;code&gt;;&lt;/code&gt; and then &lt;code&gt;d&lt;/code&gt; immediately afterwards returns the sequence of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From &lt;em&gt;Insert&lt;/em&gt; mode, escape to &lt;em&gt;Normal&lt;/em&gt; mode&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;:&lt;/code&gt; to get inside the &lt;em&gt;Command&lt;/em&gt; mode, and type the &lt;code&gt;update&lt;/code&gt;
command&lt;/li&gt;
&lt;li&gt;Complete the sequence by &amp;quot;hitting&amp;quot; &lt;em&gt;Return&lt;/em&gt;, thus saving the file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third map command, &lt;code&gt;inoremap ;f &amp;lt;C-O&amp;gt;:update&amp;lt;Cr&amp;gt;&lt;/code&gt;, allows us to
type &lt;code&gt;;&lt;/code&gt; and then &lt;code&gt;f&lt;/code&gt; to return:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From &lt;em&gt;Insert&lt;/em&gt; mode, escape out to &lt;em&gt;Normal&lt;/em&gt; with &lt;code&gt;&amp;lt;C-O&amp;gt;&lt;/code&gt;, which allows
us to escape out for &lt;em&gt;ONE&lt;/em&gt; command.&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;:&lt;/code&gt; to get inside &lt;em&gt;Command&lt;/em&gt; mode, and then type &lt;code&gt;udpate&lt;/code&gt;. This is
our one command for &lt;code&gt;&amp;lt;C-O&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;quot;Hit&amp;quot; the &lt;em&gt;Return&lt;/em&gt;, thus saving the file&lt;/li&gt;
&lt;li&gt;We&amp;#39;re back in &lt;em&gt;Insert&lt;/em&gt; mode, thanks to &lt;code&gt;&amp;lt;C-O&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, the &lt;code&gt;nnoremap ;f :update&amp;lt;CR&amp;gt;&lt;/code&gt; mapping means by typing &lt;code&gt;;&lt;/code&gt; and
then &lt;code&gt;f&lt;/code&gt; in &lt;em&gt;Normal&lt;/em&gt; mode, it will result in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since, we&amp;#39;re already in &lt;em&gt;Normal&lt;/em&gt; mode, we get into &lt;em&gt;Command&lt;/em&gt; mode by
typing &lt;code&gt;:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type the &lt;code&gt;update&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;&amp;quot;Hit&amp;quot; the &lt;em&gt;Return&lt;/em&gt; key, and save the file&lt;/li&gt;
&lt;li&gt;We remain in &lt;em&gt;Normal&lt;/em&gt; mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The snippet below restricts these commands to your right hand.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;quot; ~/.vimrc
&amp;quot; *** The Right Hand system ***

inoremap ;l &amp;lt;Esc&amp;gt;
inoremap ;k &amp;lt;Esc&amp;gt;:update&amp;lt;Cr&amp;gt;
inoremap ;j &amp;lt;C-O&amp;gt;:update&amp;lt;Cr&amp;gt;
nnoremap ;j :update&amp;lt;CR&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As you can see, I kept &lt;code&gt;;&lt;/code&gt; as a prefix to my map commands. This
conveniently keeps me at homerow. I&amp;#39;ve played with mapping everything
with my right hand, but it just didn&amp;#39;t feel &amp;quot;right&amp;quot; (apologies for the
bad pun).&lt;/p&gt;

&lt;p&gt;Overall, this snippet makes me happy and I believe this will make your
day as well. If there are some other tricks
concerning escaping and saving files, please let me know in the
comments! Thanks!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Postgres_ext adds rank and common table expressions</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/09/06/postgres_ext-adds-rank-and-common-table-expressions" />
    <id>https://dockyard.com/blog/2013/09/06/postgres_ext-adds-rank-and-common-table-expressions</id>
    <category term="gems" label="Gems"/><category term="postgres_ext" label="Postgres_ext"/><category term="postgresql" label="PostgreSQL"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2013-09-06 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>In postgres_ext 2.1, complex queries get much easier</summary>
    <content type="html">&lt;p&gt;This week, I released &lt;a href=&quot;https://github.com/dockyard/postgres_ext&quot;&gt;postgres_ext&lt;/a&gt; 2.1.0, which includes
ActiveRecord::Relation methods to simplify queries that require the use
of &lt;a href=&quot;http://www.postgresql.org/docs/current/static/queries-with.html&quot;&gt;Common Table
Expressions&lt;/a&gt;
(CTEs) and the &lt;a href=&quot;http://www.postgresql.org/docs/9.2/static/functions-window.html&quot;&gt;&lt;code&gt;rank()&lt;/code&gt; windowing
function&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Common Table Expressions&lt;/h2&gt;

&lt;p&gt;In a sentence, CTEs allow you to define a temporary table to be used in
a larger query. Let&amp;#39;s look at an example:&lt;/p&gt;
&lt;div class=&quot;highlight SQL &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;WITH scores_for_game &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; *
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; scores
&lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; game_id = &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
)
&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; *
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; scores_for_game
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the above, somewhat arbitrary, example, we create a temporary table
of &lt;code&gt;scores_for_game&lt;/code&gt; which we then select from. CTEs allow you to
organize your more complex queries, and can be really helpful in certain
cases.&lt;/p&gt;

&lt;p&gt;We can make the same SQL call in ActiveRecord with postgres_ext.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.from_cte(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;scores_for_game&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.where(&lt;span class=&quot;key&quot;&gt;game_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;))
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We can also query against the CTE expression by chaining off the
resulting ActiveRecord::Relation&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.from_cte(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;scores_for_game&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.where(&lt;span class=&quot;key&quot;&gt;game_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;)).where(&lt;span class=&quot;key&quot;&gt;user_id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;would generate the following:&lt;/p&gt;
&lt;div class=&quot;highlight SQL &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;WITH scores_for_game &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; *
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; scores
&lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; game_id = &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
)
&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; *
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; scores_for_game
&lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; scores_for_game.user_id = &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can also include CTEs in your normal queries to join against by
using &lt;code&gt;with&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.with(&lt;span class=&quot;key&quot;&gt;my_games&lt;/span&gt;: &lt;span class=&quot;constant&quot;&gt;Game&lt;/span&gt;.where(&lt;span class=&quot;key&quot;&gt;id&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;)).joins(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;JOIN my_games ON scores.game_id = my_games.id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;will generate the following SQL:&lt;/p&gt;
&lt;div class=&quot;highlight SQL &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;WITH my_games &lt;span class=&quot;keyword&quot;&gt;AS&lt;/span&gt; (
&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; games.*
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; games
&lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; games.id = &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
)
&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; *
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; scores
&lt;span class=&quot;keyword&quot;&gt;JOIN&lt;/span&gt; my_games
&lt;span class=&quot;keyword&quot;&gt;ON&lt;/span&gt; scores.games_id = my_games.id
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Rank&lt;/h2&gt;

&lt;p&gt;PostgreSQL provides a &lt;code&gt;rank&lt;/code&gt; windowing function, which will take into
account ties when ranking results. You would add rank to your
projection, like the following example:&lt;/p&gt;
&lt;div class=&quot;highlight SQL &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; scores.*, rank() &lt;span class=&quot;keyword&quot;&gt;OVER&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;BY&lt;/span&gt; scores.points &lt;span class=&quot;directive&quot;&gt;DESC&lt;/span&gt;)
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; scores
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The results set will return ordered by the rank, which is determined the
order passed into the &lt;code&gt;rank&lt;/code&gt;&amp;#39;s &lt;code&gt;OVER&lt;/code&gt;. In the above example, the scores
would be ranked by their scores descending, so highest score first. If
there was a tie at first place between two scores, they would both
ranked 1, and the next result would be ranked &lt;code&gt;3&lt;/code&gt;. We can achieve the
same in ActiveRecord with postgres_ext:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.ranked(&lt;span class=&quot;key&quot;&gt;points&lt;/span&gt;: &lt;span class=&quot;symbol&quot;&gt;:desc&lt;/span&gt;)
&lt;span class=&quot;comment&quot;&gt;# or&lt;/span&gt;
&lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.ranked(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;points desc&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Rank will rank independently of any sort order applied to the query, so
you could have your scores ranked by points, but then ordered by their
creation time.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.ranked(&lt;span class=&quot;key&quot;&gt;points&lt;/span&gt;: &lt;span class=&quot;symbol&quot;&gt;:desc&lt;/span&gt;).order(&lt;span class=&quot;symbol&quot;&gt;:created_at&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;will generate the following query:&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; scores.*, rank() &lt;span class=&quot;keyword&quot;&gt;OVER&lt;/span&gt; (&lt;span class=&quot;keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;BY&lt;/span&gt; scores.points &lt;span class=&quot;directive&quot;&gt;DESC&lt;/span&gt;)
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; scores
&lt;span class=&quot;keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;BY&lt;/span&gt; scores.created_at &lt;span class=&quot;directive&quot;&gt;ASC&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Also, if you apply a sort order to your relation, and want to sort by
it, you do not have to tell ranked what order you&amp;#39;d like to use, as it
will reuse the order. &lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Score&lt;/span&gt;.ranked.order(&lt;span class=&quot;key&quot;&gt;points&lt;/span&gt;: &lt;span class=&quot;symbol&quot;&gt;:desc&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;One thing to watch out for if you use &lt;code&gt;ranked&lt;/code&gt; without an explicit
order and want to call &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-first&quot;&gt;&lt;code&gt;first&lt;/code&gt;&lt;/a&gt;
off your relation, if the results of the
relation have yet to be retrieved, the first will use your table&amp;#39;s
primary key for an &lt;code&gt;ORDER BY&lt;/code&gt; statement on the query. This has already
bitten us before we discovered the behavior of &lt;code&gt;first&lt;/code&gt;. To avoid this
behavior in &lt;code&gt;first&lt;/code&gt;, use
&lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-take&quot;&gt;&lt;code&gt;take&lt;/code&gt;&lt;/a&gt;
which does not use any implied order.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ve been using CTEs and rank on one of our client projects, and it&amp;#39;s
already cleaned up the &lt;code&gt;from_sql&lt;/code&gt; queries we were previously
using. Let us know if you hit any snags, or have any suggestions on how
else we can make complex SQL queries easier to call from ActiveRecord!
We only implement the &lt;code&gt;rank&lt;/code&gt; windowing function right now, but plan to
add the others shortly.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Computed Properties in Ember.Js</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/09/04/computed_properties_in_ember_js" />
    <id>https://dockyard.com/blog/2013/09/04/computed_properties_in_ember_js</id>
    <category term="ember" label="Ember.js"/>
    <published>2013-09-04 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Alex Navasardyan</name></author>
    <summary>Computed Properties magic explained</summary>
    <content type="html">&lt;p&gt;Note: Short version of this post is a part of &lt;a href=&quot;http://emberjs.com/guides/object-model/computed-properties/&quot;&gt;Ember.Js
Guides&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;What Are Computed Properties?&lt;/h2&gt;

&lt;p&gt;In a nutshell, it&amp;#39;s a property whose value is computed the first time
it&amp;#39;s asked for. You can define the computed property as a function and
when someone asks for it, Ember will automatically invoke the function
and treat the return value like value of the property.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s a very well-known example:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Person = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;function&quot;&gt;fullName&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) + &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; + &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }.property(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; ironMan = Person.create({
  &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Tony&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;:  &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Stark&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
});

ironMan.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;comment&quot;&gt;// &amp;quot;Tony Stark&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The code above defines a computed property &lt;code&gt;fullName&lt;/code&gt; by calling
&lt;code&gt;property()&lt;/code&gt; on the function with two dependencies &lt;code&gt;firstName&lt;/code&gt; and
&lt;code&gt;lastName&lt;/code&gt; and whenever it gets called, it returns &lt;code&gt;firstName&lt;/code&gt; + &lt;code&gt;lastName&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Inception&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s take a look at another example. Say we want to add a description
computed property to &lt;code&gt;App.Person&lt;/code&gt;. It will aggregate other properties like
&lt;code&gt;fullName&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;, &lt;code&gt;country&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Person = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;age&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;country&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;function&quot;&gt;fullName&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) + &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; + &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }.property(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;),
  &lt;span class=&quot;function&quot;&gt;description&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) + &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;; Age: &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; +
           &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) + &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;; Country: &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; +
           &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }.property(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; captainAmerica = Person.create({
  &lt;span class=&quot;key&quot;&gt;fullName&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Steve Rogers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;age&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;80&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;country&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;USA&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
});

captainAmerica.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;comment&quot;&gt;// &amp;quot;Steve Rogers; Age: 80; Country: USA&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice that you can use an existing computed property as a dependency for a
new one.&lt;/p&gt;

&lt;h2&gt;Caching&lt;/h2&gt;

&lt;p&gt;By default, all computed properties are cached. That means that once you
requested the value of computed property (called &lt;code&gt;get&lt;/code&gt; on it), it&amp;#39;s going
to compute and cache its value:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;captainAmerica.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;comment&quot;&gt;// computes the value and returns &amp;quot;Steve Rogers; Age: 80; Country: USA&amp;quot;&lt;/span&gt;
captainAmerica.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;comment&quot;&gt;// returns cached &amp;quot;Steve Rogers; Age: 80; Country: USA&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A computed property gets recomputed when any of the properties it depends on change:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;captainAmerica.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;United States of America&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
captainAmerica.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;comment&quot;&gt;// computes the value and returns&amp;quot;Steve Rogers; Age: 80; Country: United States of America&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Read Only&lt;/h2&gt;

&lt;p&gt;This property is &lt;code&gt;false&lt;/code&gt; by default. You won&amp;#39;t be able to set the value of
the computed property if you call &lt;code&gt;readOnly&lt;/code&gt; on it:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Person = Ember.Object.extend({
  &lt;span class=&quot;function&quot;&gt;description&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;comment&quot;&gt;// implementation&lt;/span&gt;
  }.property(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).readOnly()
});

&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; captainAmerica = Person.create();
captainAmerica.set(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hero&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
&lt;span class=&quot;comment&quot;&gt;// &amp;quot;Cannot Set: description on: &amp;lt;(unknown mixin):ember133&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Alternative syntax for defining Computed Properties&lt;/h2&gt;

&lt;p&gt;This code:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Person = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;fullName&lt;/span&gt;: Ember.computed(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) + &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; + &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  })
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;does exactly the same thing as this code:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Person = Ember.Object.extend({
  &lt;span class=&quot;key&quot;&gt;firstName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;key&quot;&gt;lastName&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;null&lt;/span&gt;,
  &lt;span class=&quot;function&quot;&gt;fullName&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) + &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; + &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.get(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;);
  }.property(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;with the difference that the first example works if you disable &lt;a href=&quot;http://emberjs.com/api/#property_EXTEND_PROTOTYPES&quot;&gt;Ember&amp;#39;s
prototype extension&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;How are Computed Properties different from Observers and Bindings?&lt;/h2&gt;

&lt;p&gt;The concept of &lt;code&gt;observer&lt;/code&gt; is pretty simple. You have something that you want to track the change of. You add an observer to it, so next time it changes, a certain event is going to be fired notifying you that that something has changed.&lt;/p&gt;

&lt;p&gt;There are two types of observers: &lt;code&gt;before&lt;/code&gt; (observesBefore) and &lt;code&gt;after&lt;/code&gt; (observes). When observer event (callback) is fired, it&amp;#39;s called with two arguments: &lt;code&gt;obj&lt;/code&gt; and &lt;code&gt;keyName&lt;/code&gt;. It doesn&amp;#39;t pass the value of the property to the event (callback). The reason is because the property you&amp;#39;re watching might be lazily computed.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Observers&lt;/code&gt; are used by CP internally to invalidate CP&amp;#39;s cache when its dependency keys were changed. Observers (like CPs) don&amp;#39;t use runloop magic (fired &amp;quot;right away&amp;quot;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Observers&lt;/code&gt; are not going to fire if the value is unchanged from before (changing existing &lt;code&gt;lastName&lt;/code&gt; from &lt;code&gt;Stark&lt;/code&gt; to &lt;code&gt;Stark&lt;/code&gt; won&amp;#39;t trigger the observer callback).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Bindings&lt;/code&gt; is an internal concept that is not meant to be used. I&amp;#39;m not saying you can&amp;#39;t, it&amp;#39;s better not to. Typically, you don&amp;#39;t need to use it in your application, using CP is plenty enough.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Bindings&lt;/code&gt; are meant to keep a property of two objects in sync. Their update (sync) happens through run loop, so there might be a period of time when two objects have the same property with different values and only by the end of a &lt;code&gt;sync&lt;/code&gt; queue those values are going to be the same.&lt;/p&gt;

&lt;p&gt;For example, in Ember those two objects are controller and view (any time a controller&amp;#39;s property changes, view&amp;#39;s property changes as well).&lt;/p&gt;

&lt;h2&gt;What do I use and when?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Computed properties&lt;/strong&gt; are good for combining other properties or doing
transformations on the property.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observers&lt;/strong&gt; are good for tracking changes of a property and reacting to
them. Observers should contain behaviour that reacts to the change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bindings&lt;/strong&gt; are used to make sure that the properties from the different objects
are in sync. They are rarely used and most of the times can be replaced
with computed properties.&lt;/p&gt;

&lt;h2&gt;Futher reading&lt;/h2&gt;

&lt;p&gt;You can read more about Computed Properties and Ember&amp;#39;s Object Model
over
&lt;a href=&quot;http://emberjs.com/guides/object-model/computed-properties/&quot;&gt;here&lt;/a&gt;.
Happy Coding!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Alex Navasardyan is a DockYarder!</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2013/09/04/alex-navasardyan-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2013/09/04/alex-navasardyan-is-a-dockyarder</id>
    <category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2013-09-04 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Our first fulltime Ember.js dev</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/PyRe08M.png&quot; alt=&quot;Alex&quot;&gt;&lt;/p&gt;

&lt;p&gt;Alex has been friend for a while now, I got to know him when I started
attending the &lt;a href=&quot;www.meetup.com/Boston-Ember-js/&quot;&gt;Boston Ember meetup&lt;/a&gt;.
Alex has been a very active in the Ember.js community and helped with
the 1.0 release last week as well as
&lt;a href=&quot;http://emberjs.com/list-view/&quot;&gt;Ember.ListView&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We&amp;#39;re very dedicated to the future of Ember.js and with Alex on board
we&amp;#39;re well on our way to building out one of the best teams around.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/twokul&quot;&gt;Follow Alex on Twitter&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Announcing Postgres_ext version 1.0 and 2.0</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/08/23/announcing-postgres_ext-version-1-0-and-2-0" />
    <id>https://dockyard.com/blog/2013/08/23/announcing-postgres_ext-version-1-0-and-2-0</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="gems" label="Gems"/><category term="postgres_ext" label="Postgres_ext"/><category term="postgresql" label="PostgreSQL"/>
    <published>2013-08-23 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Today, I released not 1 but 2 versions of PostgresExt</summary>
    <content type="html">&lt;p&gt;Two versions of PostgresExt have been released today.&lt;/p&gt;

&lt;h2&gt;1.0.0 (and the 1-0-stable branch)&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/dockyard/postgres_ext/tree/v1.0.0&quot;&gt;1.0.0&lt;/a&gt;
 version is the first production release of PostgresExt. It
supports Rails 3.2.x, adding in both data type and advanced querying
support for ActiveRecord and Arel.&lt;/p&gt;

&lt;h2&gt;2.0.0&lt;/h2&gt;

&lt;p&gt;I have also released version &lt;a href=&quot;https://github.com/dockyard/postgres_ext/tree/v2.0.0&quot;&gt;2.0.0&lt;/a&gt;,
which supports ActiveRecord and Arel 4.0.x. Most of the 1.0.0 code
is gone from 2.0.0, since Rails 4.0.0 supports all the data types
that PostgresExt added to Rails 3.2.x.&lt;/p&gt;

&lt;h2&gt;The Future&lt;/h2&gt;

&lt;p&gt;I&amp;#39;m focusing on Rails 4.0.0 for all future features of PostgresExt. I
will gladly pull in additional features for 1.0.0, but Rails 3.2.x is no
longer the primary focus of PostgresExt. Maintenance on 1.0.0 will be
minimal, since &lt;a href=&quot;http://weblog.rubyonrails.org/2013/2/24/maintenance-policy-for-ruby-on-rails/&quot;&gt;Rails 3.2.x will no longer be receiving releases for bug
fixes&lt;/a&gt;,
but pull requests for bug fixes would be graciously accepted.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Design Patterns: The Observer Pattern</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/08/20/design-patterns-observer-pattern" />
    <id>https://dockyard.com/blog/2013/08/20/design-patterns-observer-pattern</id>
    <category term="ruby" label="Ruby"/><category term="design-patterns" label="Design Patterns"/>
    <published>2013-08-20 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>NSA Edition: Exploring design patterns and their use cases</summary>
    <content type="html">&lt;p&gt;Note: We won&amp;#39;t be going over the Ruby
module
&lt;a href=&quot;http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html&quot;&gt;&lt;em&gt;Observable&lt;/em&gt;&lt;/a&gt;.
Instead, we&amp;#39;ll building out the pattern ourselves.&lt;/p&gt;

&lt;h2&gt;Your First Day at the NSA&lt;/h2&gt;

&lt;p&gt;Welcome to the National Security Agency, &lt;a href=&quot;http://www.forodecostarica.com/attachments/201136d1337091462-los-gringos-se-burlan-de-nuestro-pais-agent-smith.jpg&quot;&gt;Agent
Smith&lt;/a&gt;.
You have quite an impressive background, and we believe your &amp;quot;go-getter&amp;quot;
attitude will instill a new kind of vigor within the organization.&lt;/p&gt;

&lt;p&gt;Your cubicle is down to the left... here are some NDAs for
you to fill out. I&amp;#39;ll swing by your desk in the afternoon and pick them
up from you later. Oh, and before I forget, here is your first assignment.&lt;/p&gt;

&lt;p&gt;Go get &amp;#39;em, tiger!&lt;/p&gt;

&lt;h2&gt;The First Assignment&lt;/h2&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Agent Smith
Spook First Class
[REDACTED]
NSA                                                     08-20-[REDACTED]

                     Operation [REDACTED] Observers

Welcome, Agent Smith:

Bluntly, we&#39;d like to track everyone&#39;s emails.

Attached are two documents.

The first document will show you the basic structure of a typical email,
and the second document will provide you a basic profile of a suspicious
person.

If there are any questions, please reach me at [REDACTED].

Best of luck,





Agent [REDACTED]
[REDACTED]
[REDACTED]
NSA
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# Document 1:&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;# Basic structure of an email&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Email&lt;/span&gt;
  extend &lt;span class=&quot;predefined-constant&quot;&gt;self&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;send&lt;/span&gt;(subject, sender, receiver)
    puts &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;%Q[&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;
      Subject: &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;subject&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;
      From:    &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;sender&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;@example.com
      To:      &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;receiver&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;@example.com
      Date:    &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;constant&quot;&gt;Time&lt;/span&gt;.now.asctime&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# Document 2:&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;# Characteristics of a suspicious person&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Person&lt;/span&gt;
  include &lt;span class=&quot;constant&quot;&gt;Email&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(name)
    &lt;span class=&quot;instance-variable&quot;&gt;@name&lt;/span&gt; = name
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;send_email&lt;/span&gt;(subject, receiver)
    &lt;span class=&quot;constant&quot;&gt;Email&lt;/span&gt;.send(subject, name, receiver)
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As we look through the &lt;code&gt;Email&lt;/code&gt; module, we see that it contains
&lt;code&gt;Email.send&lt;/code&gt; which takes three arguments: &lt;code&gt;subject&lt;/code&gt;, &lt;code&gt;sender&lt;/code&gt;, and
&lt;code&gt;receiver&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Gazing at the suspicious &lt;code&gt;Person&lt;/code&gt; class, we see that it includes the
&lt;code&gt;Email&lt;/code&gt; module. &lt;code&gt;Person#send_email&lt;/code&gt; takes two parameters: a subject
and a receiver. &lt;code&gt;Person#name&lt;/code&gt; will stand in as the sender of the email.&lt;/p&gt;

&lt;p&gt;Hypothetically, let&amp;#39;s see how a suspicious person would send an email:&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;bill = Person.new &#39;Bill&#39;
bill.send_email &#39;Fishing Trip&#39;, &#39;Fred&#39;
  # =&amp;gt;
      Subject: Fishing Trip
      From:    Bill@example.com
      To:      Fred@example.com
      Date:    Wed Aug 16 20:35:09 2006
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Hmm... as you sit in your cubicle, you ponder the numerous possible ways of
tracking emails. You won&amp;#39;t need anything too complicated, just
something to kick off a notification once an email has been sent.&lt;/p&gt;

&lt;p&gt;Volia! You realize you can use the &lt;em&gt;Observer&lt;/em&gt; pattern!&lt;/p&gt;

&lt;h2&gt;The Subject and its Observers&lt;/h2&gt;

&lt;p&gt;First, let&amp;#39;s start off by creating two &lt;em&gt;observer&lt;/em&gt; classes,
&lt;code&gt;Alert&lt;/code&gt; and &lt;code&gt;Agent&lt;/code&gt; classes.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Alert&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;gotcha&lt;/span&gt;(person)
    puts &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;!!! ALERT: &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;person.name.upcase&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; SENT AN EMAIL !!!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Agent&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;gotcha&lt;/span&gt;(person)
    puts &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;!!! TIME TO DETAIN &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;person.name.upcase&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; !!!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, let&amp;#39;s create a &lt;code&gt;Subject&lt;/code&gt; module.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Subject&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:observers&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@observers&lt;/span&gt; = []
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;add_observer&lt;/span&gt;(*observers)
    observers.each { |observer| &lt;span class=&quot;instance-variable&quot;&gt;@observers&lt;/span&gt; &amp;lt;&amp;lt; observer }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;delete_observer&lt;/span&gt;(*observers)
    observers.each { |observer| &lt;span class=&quot;instance-variable&quot;&gt;@observers&lt;/span&gt;.delete(observer) }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  private

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;notify_observers&lt;/span&gt;
    observers.each { |observer| observer.gotcha(&lt;span class=&quot;predefined-constant&quot;&gt;self&lt;/span&gt;) }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here within the &lt;code&gt;Subject#initialize&lt;/code&gt;, we create an empty array which
will contain a list of &lt;em&gt;observers&lt;/em&gt;. &lt;code&gt;Subject#add_observer&lt;/code&gt; simply pushes
our desired &lt;em&gt;observers&lt;/em&gt; into the array.&lt;/p&gt;

&lt;p&gt;Finally, we can alter the suspicious &lt;code&gt;Person&lt;/code&gt; class, which will act as
the &lt;em&gt;subject&lt;/em&gt; class. Let&amp;#39;s include the &lt;code&gt;Subject&lt;/code&gt; module now.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Person&lt;/span&gt;
  include &lt;span class=&quot;constant&quot;&gt;Email&lt;/span&gt;, &lt;span class=&quot;constant&quot;&gt;Subject&lt;/span&gt;
  attr_reader &lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(name)
    &lt;span class=&quot;comment&quot;&gt;# &#39;super&#39; requires a parentheses because we&#39;re calling&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;# super on the superclass, &#39;Subject&#39;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;super&lt;/span&gt;()
    &lt;span class=&quot;instance-variable&quot;&gt;@name&lt;/span&gt; = name
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;send_email&lt;/span&gt;(subject, receiver)
    &lt;span class=&quot;constant&quot;&gt;Email&lt;/span&gt;.send(subject, name, receiver)
    notify_observers
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Subject#notify_observers&lt;/code&gt; calls &lt;code&gt;#gotcha&lt;/code&gt; on each &lt;em&gt;observer&lt;/em&gt;, which
informs each &lt;em&gt;observer&lt;/em&gt; that &lt;code&gt;Person#send_email&lt;/code&gt; has been kicked off.&lt;/p&gt;

&lt;p&gt;Now let&amp;#39;s give it a whirl...&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;alert = &lt;span class=&quot;constant&quot;&gt;Alert&lt;/span&gt;.new
agent = &lt;span class=&quot;constant&quot;&gt;Agent&lt;/span&gt;.new

bill = &lt;span class=&quot;constant&quot;&gt;Person&lt;/span&gt;.new &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Bill&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

bill.add_observer alert, agent   &lt;span class=&quot;comment&quot;&gt;# Bill now has two observers watching him&lt;/span&gt;

bill.send_email &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Fishing Trip&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Fred&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# =&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;key&quot;&gt;Subject&lt;/span&gt;: &lt;span class=&quot;constant&quot;&gt;Fishing&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;Trip&lt;/span&gt;
      &lt;span class=&quot;key&quot;&gt;From&lt;/span&gt;:    &lt;span class=&quot;constant&quot;&gt;Bill&lt;/span&gt;&lt;span class=&quot;instance-variable&quot;&gt;@example&lt;/span&gt;.com
      &lt;span class=&quot;key&quot;&gt;To&lt;/span&gt;:      &lt;span class=&quot;constant&quot;&gt;Fred&lt;/span&gt;&lt;span class=&quot;instance-variable&quot;&gt;@example&lt;/span&gt;.com
      &lt;span class=&quot;key&quot;&gt;Date&lt;/span&gt;:    &lt;span class=&quot;constant&quot;&gt;Wed&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;Aug&lt;/span&gt; &lt;span class=&quot;integer&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;integer&quot;&gt;20&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;35&lt;/span&gt;:&lt;span class=&quot;integer&quot;&gt;09&lt;/span&gt; &lt;span class=&quot;integer&quot;&gt;2006&lt;/span&gt;

!!! &lt;span class=&quot;key&quot;&gt;ALERT&lt;/span&gt;: &lt;span class=&quot;constant&quot;&gt;BILL&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;SENT&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;AN&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;EMAIL&lt;/span&gt; !!!
!!! &lt;span class=&quot;constant&quot;&gt;TIME&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;TO&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;DETAIN&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;BILL&lt;/span&gt; !!!
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Perfect, it works! Now we can start protecting our freedom!&lt;/p&gt;

&lt;h2&gt;Discussion&lt;/h2&gt;

&lt;p&gt;In our example above, we have two &lt;em&gt;observers&lt;/em&gt;, the &lt;code&gt;Alert&lt;/code&gt; and &lt;code&gt;Agent&lt;/code&gt;
classes, and a &lt;em&gt;subject&lt;/em&gt;, &lt;code&gt;Person&lt;/code&gt;. By creating the &lt;code&gt;Subject&lt;/code&gt; module,
any instance of &lt;code&gt;Person&lt;/code&gt; now informs and updates any &lt;em&gt;observer&lt;/em&gt; through
&lt;code&gt;#notify_observers&lt;/code&gt;, ultimately removing any implicit coupling from &lt;code&gt;Alert&lt;/code&gt; and
&lt;code&gt;Agent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are a few similarities between the &lt;em&gt;Observer&lt;/em&gt; and
&lt;a href=&quot;http://reefpoints.dockyard.com/2013/07/25/design-patterns-strategy-pattern.html&quot;&gt;&lt;em&gt;Strategy&lt;/em&gt;&lt;/a&gt;
patterns. Both patterns employ an object (the Observer&amp;#39;s &lt;em&gt;subject&lt;/em&gt; and
the Strategy&amp;#39;s &lt;em&gt;context&lt;/em&gt;) that makes calls to another object (the
Observer&amp;#39;s &lt;em&gt;observer&lt;/em&gt; or Strategy&amp;#39;s &lt;em&gt;strategy&lt;/em&gt;). The difference between
the two patterns is the purpose and use case. The &lt;em&gt;Strategy&lt;/em&gt; pattern
relies on the &lt;em&gt;strategy&lt;/em&gt; to do the work, while the &lt;em&gt;Observer&lt;/em&gt; pattern
informs the &lt;em&gt;observers&lt;/em&gt; of what is going on with the &lt;em&gt;subject&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed this short example, thanks for reading!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Testing Context Validations</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/08/05/testing-context-validations" />
    <id>https://dockyard.com/blog/2013/08/05/testing-context-validations</id>
    <category term="context-validation" label="Context Validation"/><category term="testing" label="Testing"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="gems" label="Gems"/>
    <published>2013-08-05 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>We moved your model validations to your controller, now we&#39;re going to help you test them</summary>
    <content type="html">&lt;h2&gt;Quick Refresher on ContextValidation&lt;/h2&gt;

&lt;p&gt;A few months ago, Brian released the &lt;a href=&quot;http://reefpoints.dockyard.com/ruby/2013/05/09/context-validations.html&quot;&gt;ContextValidations gem&lt;/a&gt;.
ContextValidations moves your model validations to the controller,
allowing you to vary your validations by context, rather than relying on
conditional validations.&lt;/p&gt;

&lt;h2&gt;Let&amp;#39;s validate our user&lt;/h2&gt;

&lt;p&gt;We have a user model, that requires a password and a username when a
user signs up. They can change their username and password, but if they
can leave the password blank when updating their account, it will retain
the old password. Whenever they enter a password , it must be 9
characters or greater. We&amp;#39;re going to ignore the actual implementation
of the password saving scheme and password confirmation in this example.
Also, this example ignores setting up the test helper for &lt;a href=&quot;https://github.com/bcardarella/valid_attribute&quot;&gt;valid_attribute&lt;/a&gt;
and MiniTest::Spec.&lt;/p&gt;

&lt;h3&gt;Implementing the Tests and Validations in the Model&lt;/h3&gt;

&lt;p&gt;To test the above requirements model validations, we&amp;#39;d do the following:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;describe &lt;span class=&quot;constant&quot;&gt;OldUser&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;new user&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    subject { &lt;span class=&quot;constant&quot;&gt;OldUser&lt;/span&gt;.new &lt;span class=&quot;key&quot;&gt;password&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;password_to_confirm&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }

    it { must have_valid(&lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bob&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test1234&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    it { wont have_valid(&lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;) }
    it { must have_valid(&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;validpassword1234&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    it { wont have_valid(&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tooshort&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;existing user&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    subject { old_users(&lt;span class=&quot;symbol&quot;&gt;:example&lt;/span&gt;) }

    it { must have_valid(&lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bob&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test1234&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    it { wont have_valid(&lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;) }
    it { must have_valid(&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;validpassword1234&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    it { wont have_valid(&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tooshort&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And here is the implementation of the model:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;OldUser&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  attr_accessor &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;
  validates &lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;presence&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  validates &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;presence&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;if&lt;/span&gt;: &lt;span class=&quot;symbol&quot;&gt;:new_record?&lt;/span&gt;
  validates &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;length&lt;/span&gt;: { &lt;span class=&quot;key&quot;&gt;minimum&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;9&lt;/span&gt; }, &lt;span class=&quot;key&quot;&gt;allow_blank&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Implementing the Tests and Validations in the Controller with ContextValidations&lt;/h3&gt;

&lt;p&gt;We&amp;#39;ve been using ContextValidations with our client work since its
release and realized we could unit test the controller to test the
validations.&lt;/p&gt;

&lt;p&gt;Our unit tests for the controller are here:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;describe &lt;span class=&quot;constant&quot;&gt;UsersController&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#create&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    subject { &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.new(&lt;span class=&quot;key&quot;&gt;validations&lt;/span&gt;: validations_for(&lt;span class=&quot;symbol&quot;&gt;:create&lt;/span&gt;)) }

    it { must have_valid(&lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bob&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test1234&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    it { wont have_valid(&lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;) }
    it { must have_valid(&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;validpassword1234&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    it { wont have_valid(&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tooshort&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#update&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    subject { &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.new(&lt;span class=&quot;key&quot;&gt;validations&lt;/span&gt;: validations_for(&lt;span class=&quot;symbol&quot;&gt;:update&lt;/span&gt;)) }

    it { must have_valid(&lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bob&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test1234&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    it { wont have_valid(&lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;) }
    it { must have_valid(&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;validpassword1234&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    it { wont have_valid(&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;tooshort&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note the use of &lt;code&gt;validations_for&lt;/code&gt;. It is a MiniTest
helper method defined by ContextValidations, which looks up the name
of the controller from the describe block, creates an instance of it,
and retrieves the validations for the context passed in. This prevents
you from needing to create your own instance and calling &lt;code&gt;validations&lt;/code&gt;
on it. The resulting tests end up looking very similar to what your
model tests would look like.&lt;/p&gt;

&lt;p&gt;Our model implementation is very light:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;User&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  include &lt;span class=&quot;constant&quot;&gt;ContextValidations&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Model&lt;/span&gt;

  attr_accessor &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And our validations are defined in the controller:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;UsersController&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ApplicationController&lt;/span&gt;
  include &lt;span class=&quot;constant&quot;&gt;ContextValidations&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Controller&lt;/span&gt;

  private

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;base_validations&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:username&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;presence&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;length&lt;/span&gt;: { &lt;span class=&quot;key&quot;&gt;minimum&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;9&lt;/span&gt; }, &lt;span class=&quot;key&quot;&gt;allow_blank&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;create_validations&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;presence&lt;/span&gt;: &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;All of the examples are part of &lt;a href=&quot;https://github.com/dockyard/testing_context_validations&quot;&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Wrapping it up&lt;/h2&gt;

&lt;p&gt;As you can see, writing the validation tests for the controller are
almost identical to writing them for the model. There are a few
differences in setting up the subject for the tests, but the only major
difference is that you are testing the controller instead of the model.
If you have any feedback on the tests we came up with, feel free to let
us know!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Putting things next to things with Susy</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/07/29/putting-things-next-to-things-with-susy" />
    <id>https://dockyard.com/blog/2013/07/29/putting-things-next-to-things-with-susy</id>
    <category term="design" label="Design"/>
    <published>2013-07-29 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Angelo Simeoni</name></author>
    <summary>The little grid framework that can</summary>
    <content type="html">&lt;p&gt;I&amp;#39;ve often lamented that one of the most challenging things to do on the front end is to put things next to other things. Things on top of things? Easy. Things by themselves? Piece of cake. This thing next to that thing? Things just got complicated.&lt;/p&gt;

&lt;p&gt;Should you roll your own layout, coming up with and refining conventions, browser testing to make sure everything still works? Do you rely on a front-end framework and all of the cluttered, confusing markup that comes going from that route? &lt;/p&gt;

&lt;p&gt;What about something different? This is where Susy saves the day.&lt;/p&gt;

&lt;h2&gt;The little framework that can&lt;/h2&gt;

&lt;p&gt;Susy is a grid framework for Compass. With Susy, you simply define your grid settings and start laying things out. If you want to come back and adjust your grid later, that&amp;#39;s totally fine. Susy will recalculate all your layouts.&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;error&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;total-columns&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;12&lt;/span&gt;
&lt;span class=&quot;error&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;column-width&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;4em&lt;/span&gt;
&lt;span class=&quot;error&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;gutter-width&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;1em&lt;/span&gt;
&lt;span class=&quot;error&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;grid-padding&lt;/span&gt;: &lt;span class=&quot;error&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;gutter-width&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Two main mixins do the bulk of the lifting. These are &amp;#39;container&amp;#39; and &amp;#39;span-columns&amp;#39;. Container is used to define the container of the grid. Span-columns is applied to elements within a container context. The syntax is easy.&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.page&lt;/span&gt;
  +&lt;span class=&quot;tag&quot;&gt;container&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;article&lt;/span&gt;
    +&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;(&lt;span class=&quot;float&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;float&quot;&gt;12&lt;/span&gt;)
  &lt;span class=&quot;tag&quot;&gt;aside&lt;/span&gt;
    +&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;(&lt;span class=&quot;float&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;omega&lt;/span&gt;, &lt;span class=&quot;float&quot;&gt;12&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This makes &amp;#39;.page&amp;#39; the grid container. The article takes up eight of twelve columns, the aside the final (omega) four of twelve columns.&lt;/p&gt;

&lt;p&gt;Susy really shines at figuring stuff out on its own. Say I wanted to have two columns of different widths with different padding for each column, both nested within the article above?&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;article&lt;/span&gt;
  +&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;(&lt;span class=&quot;float&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;float&quot;&gt;12&lt;/span&gt;)
  &lt;span class=&quot;class&quot;&gt;.one&lt;/span&gt;
    +&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;(&lt;span class=&quot;float&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;float&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;float&quot;&gt;1em&lt;/span&gt;)
  &lt;span class=&quot;class&quot;&gt;.two&lt;/span&gt;
    +&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;(&lt;span class=&quot;float&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;tag&quot;&gt;omega&lt;/span&gt;, &lt;span class=&quot;float&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;class&quot;&gt;.5em&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Where did the seven columns come from? Susy doesn&amp;#39;t care. They are within the context of the article. Susy will figure out the math and make seven columns. The third option is the column padding. Susy will do the math there too. Thanks, Susy!&lt;/p&gt;

&lt;h2&gt;Susy, breakpoints and you&lt;/h2&gt;

&lt;p&gt;Susy is made to build responsive grids. The default layout is called &amp;#39;magic&amp;#39;. It&amp;#39;s a fixed width layout that fluidly scales if the viewport is smaller than the width of the grid. You can also opt for a fully fluid layout, or a static layout for pixel precision.&lt;/p&gt;

&lt;p&gt;Any of these layouts can be further modified with the +at-breakpoint mixin. This mixin makes accessing media queries within the context of our grid simple and straightforward.&lt;/p&gt;
&lt;div class=&quot;highlight css &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;.one&lt;/span&gt;, &lt;span class=&quot;class&quot;&gt;.two&lt;/span&gt;
  +&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;t&lt;/span&gt;(&lt;span class=&quot;float&quot;&gt;30em&lt;/span&gt;)
    +&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;s&lt;/span&gt;(&lt;span class=&quot;float&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;float&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;class&quot;&gt;.5em&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;The one true grid&lt;/h2&gt;

&lt;p&gt;Everything Susy does is within context of a grid. You can  define multiple grids, and nest these grids inside one another. You can define abritrary values within any context. Many useful features, such as push, pull, and bleed are there to make life even easier.&lt;/p&gt;

&lt;p&gt;With all of this power comes some responsiblity. As with any tool, Susy just does what you ask it to do. It cannot explain  why your layout isn&amp;#39;t working. If you try to put too many things inside a grid, your layout will break. I&amp;#39;d recommend taking Susy for a spin. It&amp;#39;s really easy to &lt;a href=&quot;http://susy.oddbird.net/guides/getting-started/&quot;&gt;get started&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Design Patterns: The Strategy Pattern</title>
    <link rel="alternate" href="https://dockyard.com/blog/2013/07/25/design-patterns-strategy-pattern" />
    <id>https://dockyard.com/blog/2013/07/25/design-patterns-strategy-pattern</id>
    <category term="design-patterns" label="Design Patterns"/><category term="ruby" label="Ruby"/>
    <published>2013-07-25 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>Exploring design patterns and their use cases</summary>
    <content type="html">&lt;h2&gt;Walls are sooooo last week...&lt;/h2&gt;

&lt;p&gt;In our last post, we discussed the &lt;em&gt;&lt;a href=&quot;http://reefpoints.dockyard.com/ruby/2013/07/10/design-patterns-template-pattern.html&quot;&gt;Template
Method&lt;/a&gt;&lt;/em&gt;
pattern and its benefits, finding it most useful when we need to simply shape
behavior of &lt;em&gt;subclasses&lt;/em&gt;. However, due to the reliance on &lt;em&gt;inheritance&lt;/em&gt;,
there are a couple of limitations to this pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subclasses are tightly bound to a superclass or baseclass&lt;/li&gt;
&lt;li&gt;Runtime flexibility is hindered&lt;/li&gt;
&lt;li&gt;Only a portion of the desired alogrithm is varied&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thankfully, there is another design pattern that resolves these
problems: the &lt;em&gt;Strategy&lt;/em&gt; pattern.&lt;/p&gt;

&lt;h2&gt;Summertime and the Livin&amp;#39; is Easy&lt;/h2&gt;

&lt;h3&gt;Hot dogs, hamburgers, and veggie patties&lt;/h3&gt;

&lt;p&gt;It&amp;#39;s the middle of July, and there&amp;#39;s no better time to throw a day
party. Our pals are bringing the tasty beverages, so we just need to prepare the food.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ll first create a superclass &lt;code&gt;Food&lt;/code&gt; that will delagate &lt;code&gt;#type&lt;/code&gt; to its
subclasses: &lt;code&gt;HotDog&lt;/code&gt;, &lt;code&gt;Hamburger&lt;/code&gt;, and &lt;code&gt;VeggiePatty&lt;/code&gt;. Notice that this
is the &lt;em&gt;&lt;a href=&quot;http://reefpoints.dockyard.com/ruby/2013/07/10/design-patterns-template-pattern.html&quot;&gt;Template
Method&lt;/a&gt;&lt;/em&gt;
pattern in action.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Food&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;type&lt;/span&gt;
    raise &lt;span class=&quot;constant&quot;&gt;NotImplementedError&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Ask the subclass&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;HotDog&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Food&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hot dogs&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Hamburger&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Food&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hamburgers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;VeggiePatty&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Food&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;veggie patties&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, let&amp;#39;s get the grill ready.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Grill&lt;/span&gt;
  attr_accessor &lt;span class=&quot;symbol&quot;&gt;:food&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt; food
    &lt;span class=&quot;instance-variable&quot;&gt;@food&lt;/span&gt; = food
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;grilling&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Grilling the &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;food.type&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Nice. Now let&amp;#39;s get grilling! We&amp;#39;ll start with some hot dogs.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;grill = &lt;span class=&quot;constant&quot;&gt;Grill&lt;/span&gt;.new(&lt;span class=&quot;constant&quot;&gt;HotDog&lt;/span&gt;.new)
grill.grilling &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; &amp;quot;Grilling the hot dogs!&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Oh watch out, these dogs are almost done... time to throw on the
hamburger and veggie patties.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;grill.food = &lt;span class=&quot;constant&quot;&gt;Hamburger&lt;/span&gt;.new
grill.grilling &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; &amp;quot;Grilling the hamburgers!&amp;quot;&lt;/span&gt;

grill.food = &lt;span class=&quot;constant&quot;&gt;VeggiePatty&lt;/span&gt;.new
grill.grilling &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; &amp;quot;Grilling the veggie patties!&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Wasn&amp;#39;t that easy? We were able to switch out items without
creating a new class of &lt;code&gt;Grill&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Discussion&lt;/h2&gt;

&lt;h3&gt;Strategies and Context&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;Strategy&lt;/em&gt; pattern employs &lt;em&gt;strategies&lt;/em&gt;, objects of which
possess identical behavior. Our grill party relies on &lt;em&gt;strategies&lt;/em&gt; to
tell us what &lt;code&gt;#type&lt;/code&gt; of food they were. It&amp;#39;s important that all strategy objects
have the same responsiblity and support the same interface, which in our case
was &lt;code&gt;grill.grilling&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Grill&lt;/code&gt; class is our &lt;em&gt;context&lt;/em&gt; class, the operator of the
&lt;em&gt;strategies&lt;/em&gt;, which uses the &lt;code&gt;HotDog#type&lt;/code&gt;, &lt;code&gt;Hamburger#type&lt;/code&gt;, and
&lt;code&gt;VeggiePatty#type&lt;/code&gt; interchangeably.&lt;/p&gt;

&lt;p&gt;Through our contrived example, we see the immediate benefits of this
design pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Separation of concerns&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Strategies&lt;/em&gt; at runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We&amp;#39;ve achieved &lt;em&gt;separation of concerns&lt;/em&gt; by designating the &lt;code&gt;#type&lt;/code&gt;
method as our desired set of &lt;em&gt;strategies&lt;/em&gt;. &lt;code&gt;HotDog&lt;/code&gt;, &lt;code&gt;Hamburger&lt;/code&gt; and
&lt;code&gt;VeggiePatty&lt;/code&gt;  are unaware of our implementation of &lt;code&gt;Grill#grilling&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As for runtime flexibility, we&amp;#39;re able to switch out the items up on the
grill.&lt;/p&gt;

&lt;h3&gt;Special Patties: Lambdas&lt;/h3&gt;

&lt;p&gt;As we&amp;#39;re grilling our hamburger and veggies patties, a last minute guest
arrives, and she has brought some bacon, jalapeÃ±os, and onions.
Let&amp;#39;s make some custom patties, but avoid creating more subclasses of
&lt;code&gt;Food&lt;/code&gt;. What could we do here?&lt;/p&gt;

&lt;p&gt;A quick and awesome solution would be to use &lt;em&gt;lambdas&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Since we expect our &lt;em&gt;strategies&lt;/em&gt; to return &lt;code&gt;Strings&lt;/code&gt; for food &lt;code&gt;#type&lt;/code&gt;,
we can create a &lt;em&gt;lambda&lt;/em&gt; which will behave just like the other strategy
objects and return a &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;CUSTOMPATTY&lt;/span&gt; = lambda { |type| &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;type&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next, let&amp;#39;s get back to our &lt;code&gt;Grill&lt;/code&gt; class and alter the class a little
bit.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Grill&lt;/span&gt;
  attr_accessor &lt;span class=&quot;symbol&quot;&gt;:food&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt; food
    &lt;span class=&quot;instance-variable&quot;&gt;@food&lt;/span&gt; = food
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;grilling&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Grilling the &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;print_food&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  private

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;print_food&lt;/span&gt;
    food_is_string? ? food : food.type
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;food_is_string?&lt;/span&gt;
    food.is_a? &lt;span class=&quot;constant&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Since we know the &lt;em&gt;strategies&lt;/em&gt; are &lt;code&gt;Strings&lt;/code&gt;, we&amp;#39;ve created two
&lt;code&gt;private&lt;/code&gt; methods, &lt;code&gt;#print_food&lt;/code&gt; and &lt;code&gt;#food_is_string&lt;/code&gt;.
&lt;code&gt;#food_is_string&lt;/code&gt; will check if &lt;code&gt;Grill&lt;/code&gt; has received a
&lt;code&gt;String&lt;/code&gt; or not, and &lt;code&gt;#print_food&lt;/code&gt; will handle &lt;em&gt;lambdas&lt;/em&gt; or &lt;em&gt;classes&lt;/em&gt; of
food.&lt;/p&gt;

&lt;p&gt;Now let&amp;#39;s try grilling some hot dogs and custom patties!&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;jalapeÃ±os = &lt;span class=&quot;constant&quot;&gt;CUSTOMPATTY&lt;/span&gt;.call &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;spicy jalapeÃ±os patties&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
bacon = &lt;span class=&quot;constant&quot;&gt;CUSTOMPATTY&lt;/span&gt;.call &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;greasy, yummy bacon patties&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

grill = &lt;span class=&quot;constant&quot;&gt;Grill&lt;/span&gt;.new jalapeÃ±os
grill.grilling &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; &amp;quot;Grilling the spicy jalapeÃ±os patties!&amp;quot;&lt;/span&gt;

grill.food = bacon
grill.grilling &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; &amp;quot;Grilling the greasy, yummy bacon patties!&amp;quot;&lt;/span&gt;

grill.food = &lt;span class=&quot;constant&quot;&gt;HotDog&lt;/span&gt;.new
grill.grilling &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; &amp;quot;Grilling the hot dogs!&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Mmm-mmmm... That is a tasty burger.&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;Strategy&lt;/em&gt; pattern is a delagation-based design pattern, and shares
some similarities with the &lt;em&gt;Template Method&lt;/em&gt; pattern. However, instead
of depending so heavily on inheiritance between a superclass and
subclasses to use our target algorithm, we take our algorithm and
consider it as a separate object. As long as we remember the
relationship between the &lt;em&gt;strategies&lt;/em&gt; and the &lt;em&gt;context&lt;/em&gt;, we earn real
advantages over the &lt;em&gt;Template Method&lt;/em&gt;, as seen in our custom patty
example.&lt;/p&gt;

&lt;p&gt;I hope you had fun at our day party, and we&amp;#39;ll next explore the
&lt;em&gt;Observer&lt;/em&gt; pattern.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Design Patterns: The Template Method Pattern</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2013/07/10/design-patterns-template-pattern" />
    <id>https://dockyard.com/blog/ruby/2013/07/10/design-patterns-template-pattern</id>
    <category term="ruby" label="Ruby"/><category term="design-patterns" label="Design Patterns"/>
    <published>2013-07-10 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Doug Yun</name></author>
    <summary>Exploring design patterns and their use cases</summary>
    <content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;As the field of software development grows, we developers are
continuously trying to catch up with the latest technologies.
Fortunately, the craft of writing maintainable code is language
agnostic, and in this series of blogposts, we&amp;#39;ll focus on a powerful set of
timeless tools: &lt;em&gt;Design Patterns&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I highly recommend Russ Olsen&amp;#39;s book &lt;a href=&quot;http://designpatternsinruby.com/&quot;&gt;Design
Patterns in Ruby&lt;/a&gt;. Our series
will draw inspiration from it and is brief in comparison. So if you
enjoy these posts (and I hope you do!), the book will be a great
investment.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ll explore various design patterns and learn
when to apply them. Our topic for today will be the &lt;em&gt;Template Method&lt;/em&gt;
pattern, the simplest design pattern.&lt;/p&gt;

&lt;h2&gt;Our First Day in Construction&lt;/h2&gt;

&lt;h3&gt;The Right Tools&lt;/h3&gt;

&lt;p&gt;Quite simply, design patterns are just tools that help us construct software. However,
just like tools, we need to use the correct and proper one for the task. We
could use a hammer on screws, but we&amp;#39;d damage the wood planks and using a
power drill will be much more efficient. Before using any one of the numerous design patterns, it is
crucial to understand the problem we wish to solve.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It is incorrect to use a particular design pattern on the wrong
type of problem&lt;/em&gt;. In other words, it is in poor practice to use a
particular design pattern on a problem that does not require the
aforementioned design pattern.&lt;/p&gt;

&lt;h3&gt;Let&amp;#39;s Build Some Walls&lt;/h3&gt;

&lt;p&gt;Today, we&amp;#39;ve been asked by our foreman to build a couple of walls. All
the walls will share the same dimensions and will be made from the same
material (for this construction project, our foreman has given us an
&amp;quot;easy&amp;quot; set of requirements).&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# Blueprints for Wall&lt;/span&gt;
require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;minitest/autorun&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

describe &lt;span class=&quot;constant&quot;&gt;Wall&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  let(&lt;span class=&quot;symbol&quot;&gt;:wall&lt;/span&gt;) { &lt;span class=&quot;constant&quot;&gt;Wall&lt;/span&gt;.new }

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;should state its dimensions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    wall.dimensions.must_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am 30ft. long and 20ft. wide!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;should be made from brick&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    wall.made_from.must_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am made from brick!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;What a nice boss, he&amp;#39;s handed us the blueprints!
Now it&amp;#39;s just up to us to build out the &lt;code&gt;Wall&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Wall&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;dimensions&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am 30ft. long and 20ft. wide!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;made_from&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am made from brick!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Nice! Our tests pass, everybody is happy, and we&amp;#39;re off to lunch!&lt;/p&gt;

&lt;h3&gt;A Hammer or a Nailgun?&lt;/h3&gt;

&lt;p&gt;Coming back to the site, our foreman has informed us that we need more
walls. &amp;quot;That&amp;#39;s a piece of cake,&amp;quot; we reply, recalling how easy it was to
build out the &lt;code&gt;Wall&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&amp;quot;Not so fast,&amp;quot; our foreman retorts. We&amp;#39;re given new blueprints with
different wall requirements.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# Blueprints for a BrickWall&lt;/span&gt;
describe &lt;span class=&quot;constant&quot;&gt;BrickWall&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  let(&lt;span class=&quot;symbol&quot;&gt;:brick_wall&lt;/span&gt;) { &lt;span class=&quot;constant&quot;&gt;BrickWall&lt;/span&gt;.new }

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;should state its dimensions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    brick_wall.dimensions.must_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am 30ft. long and 20ft. wide!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;should be made from brick&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    brick_wall.made_from.must_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am made from brick!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;# Blueprints for a ConcreteWall&lt;/span&gt;
describe &lt;span class=&quot;constant&quot;&gt;ConcreteWall&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  let(&lt;span class=&quot;symbol&quot;&gt;:concrete_wall&lt;/span&gt;) { &lt;span class=&quot;constant&quot;&gt;ConcreteWall&lt;/span&gt;.new }

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;should state its dimensions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    concrete_wall.dimensions.must_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am 30ft. long and 20ft. wide!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;should be made from concrete&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    concrete_wall.made_from.must_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am made from concrete!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;# Blueprints for a WoodWall&lt;/span&gt;
describe &lt;span class=&quot;constant&quot;&gt;WoodWall&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  let(&lt;span class=&quot;symbol&quot;&gt;:wood_wall&lt;/span&gt;) { &lt;span class=&quot;constant&quot;&gt;WoodWall&lt;/span&gt;.new }

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;should state its dimensions&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    wood_wall.dimensions.must_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am 10ft. long and 20ft. wide!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;should be made from wood&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    wood_wall.made_from.must_equal &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am made from wood!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Hmm... A couple of ideas run through our heads. We could follow the initial &lt;code&gt;Wall&lt;/code&gt; class and
define each method, hardcoding each string output, for the &lt;code&gt;BrickWall&lt;/code&gt;, &lt;code&gt;ConcreteWall&lt;/code&gt;, and &lt;code&gt;WoodWall&lt;/code&gt;
classes. That seems like an okay idea, but we&amp;#39;d have to hard code each
instance method. What if our house requires a dozen different types of walls?&lt;/p&gt;

&lt;h3&gt;Open That Toolbox!&lt;/h3&gt;

&lt;p&gt;Sipping on our after-lunch coffee, we realize that we&amp;#39;ve got a tool right
for the job, the &lt;em&gt;Template Method&lt;/em&gt; pattern.&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;Template Method&lt;/em&gt; pattern, the creation of a &lt;em&gt;skeletal class&lt;/em&gt; will
serve as the basis for various &lt;em&gt;subclasses&lt;/em&gt; or &lt;em&gt;concrete classes&lt;/em&gt;. Within the &lt;em&gt;skeletal class&lt;/em&gt;
there are &lt;em&gt;abstract methods&lt;/em&gt;, which in turn, will be overridden by the
methods of &lt;em&gt;subclasses&lt;/em&gt;. Essentially, we&amp;#39;ll define a &lt;code&gt;Wall&lt;/code&gt; class (our
&lt;em&gt;skeletal class&lt;/em&gt;) and its &lt;em&gt;subclasses&lt;/em&gt;, &lt;code&gt;BrickWall&lt;/code&gt;, &lt;code&gt;ConcreteWall&lt;/code&gt;, and
&lt;code&gt;WoodWall&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Going over the blueprints, we notice that the three different classes of
walls each contain the methods &lt;code&gt;#dimensions&lt;/code&gt; and &lt;code&gt;#made_from&lt;/code&gt;, which
result in slighty different strings. With this knowledge, let&amp;#39;s
create our &lt;code&gt;Wall&lt;/code&gt; class and its subclasses.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
52
53
54
55
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Wall&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;dimensions&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;length&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ft. long and &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;width&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ft. wide!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;made_from&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am made from &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;material&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  private

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;length&lt;/span&gt;
    &lt;span class=&quot;integer&quot;&gt;30&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;BrickWall&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Wall&lt;/span&gt;
  private

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;width&lt;/span&gt;
    &lt;span class=&quot;integer&quot;&gt;20&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;material&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;brick&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;ConcreteWall&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Wall&lt;/span&gt;
  private

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;width&lt;/span&gt;
    &lt;span class=&quot;integer&quot;&gt;20&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;material&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;concrete&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;WoodWall&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Wall&lt;/span&gt;
  private

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;length&lt;/span&gt;
    &lt;span class=&quot;integer&quot;&gt;10&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;width&lt;/span&gt;
    &lt;span class=&quot;integer&quot;&gt;20&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;material&lt;/span&gt;
    &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;wood&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Discussion&lt;/h2&gt;

&lt;h3&gt;Hook Methods&lt;/h3&gt;

&lt;p&gt;Within the &lt;code&gt;Wall&lt;/code&gt; class we have defined a private method called &lt;code&gt;#length&lt;/code&gt;
because we see that &lt;code&gt;BrickWall&lt;/code&gt; and &lt;code&gt;ConcreteWall&lt;/code&gt; share the same
length. As for the &lt;code&gt;WoodWall&lt;/code&gt; class, we simply overwrite the &lt;code&gt;#length&lt;/code&gt;
and give it a value of &lt;code&gt;10&lt;/code&gt;. These are examples of &lt;em&gt;Hook Methods&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hook Methods&lt;/em&gt; serve two purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Override the skeletal implementation and define something new&lt;/li&gt;
&lt;li&gt;Or, accept the default implementation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please note that the default implemetation, within the skeletal class, does
not necessarily need to define a method. For example, we could have had:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Wall&lt;/span&gt;

  ...

  private

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;length&lt;/span&gt;
    raise &lt;span class=&quot;constant&quot;&gt;NotImplementedError&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Sorry, you have to override length&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;BrickWall&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Wall&lt;/span&gt;
  private

  ...

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;length&lt;/span&gt;
    &lt;span class=&quot;integer&quot;&gt;30&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the example above, the &lt;code&gt;#length&lt;/code&gt; method within the &lt;code&gt;Wall&lt;/code&gt; class
served as a placeholder for the &lt;code&gt;#length&lt;/code&gt; for the &lt;code&gt;BrickWall&lt;/code&gt;, it&amp;#39;s
&lt;em&gt;concrete class&lt;/em&gt;. Essentially, &lt;em&gt;hook methods&lt;/em&gt; inform all &lt;em&gt;concrete
classes&lt;/em&gt; that the method may require an override. If the base
implementation is undefined the subclasses must define the &lt;em&gt;hook
methods&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;Those Are Some Nice Walls&lt;/h2&gt;

&lt;p&gt;Our foreman is delighted with the results and we&amp;#39;re going to call it a
day. As we can see, using the &lt;em&gt;Template Method&lt;/em&gt; pattern is not difficult
at all. We first defined a base class, within which we defined necessary
&lt;em&gt;hook methods&lt;/em&gt; to be overridden by our &lt;em&gt;subclasses&lt;/em&gt;. Of course, this
particular design pattern does not solve every conceivable problem, but
helps keep our code clean by the use of inheritance.&lt;/p&gt;

&lt;p&gt;Next we&amp;#39;ll be discussing the &lt;em&gt;Strategy&lt;/em&gt; method pattern. Stay tuned!&lt;/p&gt;
</content>
  </entry><entry>
    <title>First Month at DockYard</title>
    <link rel="alternate" href="https://dockyard.com/blog/office/2013/07/09/first-month-at-dockyard" />
    <id>https://dockyard.com/blog/office/2013/07/09/first-month-at-dockyard</id>
    <category term="intern" label="Intern"/><category term="office" label="Office"/>
    <published>2013-07-09 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Marin Abernethy</name></author>
    <summary>Our summer intern shares her thoughts on her first month with us</summary>
    <content type="html">&lt;p&gt;I came to the programming party a little late in my &lt;a href=&quot;http://www.trincoll.edu/Pages/default.aspx&quot;&gt;college&lt;/a&gt; career, 
only having a year and a half of classroom experience under my belt. Due
to my limited CS background, I was rather anxious to start work at a
web development startup, fearing my qualifications were not up to par.
However, my feelings of inadequacy quickly subsided after starting at
DockYard! I was welcomed by a comfortable learning environment and an
atmosphere of positivity and productivity. My coworkers are very
approachable and always willing to answer my questions. Because of
DockYard&amp;#39;s intimate size I am able to see all sides of the business, and
get to know everyone in the office.&lt;/p&gt;

&lt;p&gt;It has now been a month since I began working and already I feel I am
light-years ahead of where I started. My nerves have been replaced by an
eagerness to continue learning and grow as a developer. The amount of
information that has been thrown my way is rather overwhelming. I have
already pored through 6 books, including: &lt;a href=&quot;http://pragprog.com/book/rails32/agile-web-development-with-rails-3-2&quot;&gt;Agile Web Development with
Rails&lt;/a&gt; by Sam Ruby and, &lt;a href=&quot;http://jsninja.com/&quot;&gt;Secrets of the JavaScript Ninja&lt;/a&gt; by John Resig, in
addition to other readings on &lt;a href=&quot;http://coffeescript.org&quot;&gt;CoffeeScript&lt;/a&gt;, version control (&lt;a href=&quot;http://git-scm.com&quot;&gt;git&lt;/a&gt;), and
&lt;a href=&quot;http://en.wikipedia.org/wiki/User_story&quot;&gt;user stories&lt;/a&gt;. Not to mention my introduction to vim and all the commands
that accompany it. While I cannot claim all of the information has
stuck, the exposure will surely breed understanding. I have learned that
it isn&amp;#39;t about having all the answers, but the efficiency of finding
them that is important.&lt;/p&gt;

&lt;p&gt;In addition to all the reading, I have worked on a small side project: a
simple blog site (my introduction to &lt;a href=&quot;http://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;test-driven
development&lt;/a&gt;) that I
rebuilt 3 times, each time adding more features. The saying, &amp;quot;repetition
is the mother of all learning&amp;quot;, has certainly resonated with me after
this exercise.  Also &lt;a href=&quot;http://en.wikipedia.org/wiki/Pair_programming&quot;&gt;pair programming&lt;/a&gt; with others in the office has also
been extremely helpful, giving me an idea of the day-to-day. Overall, I
feel lucky to be at DockYard in the midst of the growing field of web
development. Already I can say my experience has been invaluable and I
thoroughly look forward to the rest of the summer.&lt;/p&gt;
</content>
  </entry><entry>
    <title>DockYard Acquires Dobot</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2013/07/08/dockyard-acquires-dobot" />
    <id>https://dockyard.com/blog/announcement/2013/07/08/dockyard-acquires-dobot</id>
    <category term="announcement" label="Announcement"/><category term="office" label="Office"/><category term="business" label="Business"/>
    <published>2013-07-08 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Joining forces</summary>
    <content type="html">&lt;p&gt;Today I&amp;#39;m very happy to announce that we have acquired local design firm
&lt;a href=&quot;http://dobotdo.com&quot;&gt;Dobot&lt;/a&gt;, its two partners Steven &amp;amp; Logan have joined us full-time.
This is a huge move for DockYard, and a simple one for Dobot (they have
been working out of our office for the past few months so they don&amp;#39;t
actually need to move anywhere).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/5vrk992.gif&quot; alt=&quot;DockYard acquires Dobot&quot;&gt;&lt;/p&gt;

&lt;p&gt;Please see the announcement for &lt;a href=&quot;http://reefpoints.dockyard.com/announcement/2013/07/08/steven-trevathan-is-a-dockyarder.html&quot;&gt;Steven
Trevathan&lt;/a&gt;
and the announcement for &lt;a href=&quot;http://reefpoints.dockyard.com/announcement/2013/07/08/logan-faerber-is-a-dockyarder.html&quot;&gt;Logan
Faerber&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Steven Trevathan is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2013/07/08/steven-trevathan-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2013/07/08/steven-trevathan-is-a-dockyarder</id>
    <category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2013-07-08 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>DockYard absorbs Dobot!</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/XbSfLIm.jpg&quot; alt=&quot;Steven&quot;&gt;&lt;/p&gt;

&lt;p&gt;I&amp;#39;m very happy to announce today that DockYard has joined forces with
Boston design firm Dobot! Leader designer Steven Trevathan has come on
as a partner and Creative Director (until we come up with a title he
prefers) of DockYard.&lt;/p&gt;

&lt;p&gt;This is a huge step forward for us. While we have had in-house designers
we have been actually leaning on Steven from time to time for our
concept design needs. Now with Steven coming on as part of our team he
will focus on building out the design side of DockYard and putting
together a formal concept design process for us.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/strevat&quot;&gt;Follow Steven on Twitter&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Logan Faerber is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2013/07/08/logan-faerber-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2013/07/08/logan-faerber-is-a-dockyarder</id>
    <category term="announcement" label="Announcement"/><category term="office" label="Office"/>
    <published>2013-07-08 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>DockYard absorbs Dobot!</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/hmv9VHG.jpg&quot; alt=&quot;Logan&quot;&gt;
Along with his other fellow Dobot-er we welcome Logan Faerber to the
DockYard team today!&lt;/p&gt;

&lt;p&gt;Logan is a &lt;a href=&quot;http://www.loganfaerber.com/&quot;&gt;kick ass illustrator&lt;/a&gt; who
has done work for New York Life, Dynamo Labs, CareShare, CustomMade,
&lt;a href=&quot;http://www.biowarestore.com/garrus-screenprint-poster.html&quot;&gt;Bioware&lt;/a&gt;,
and &lt;a href=&quot;http://www.archaia.com/archaia-titles/hawken-genesis/&quot;&gt;Archaia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Logan has been working out of our office for the last few months and we
are excited to have his unique talents at DockYard.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/loganfaerber&quot;&gt;Follow Logan on Twitter&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Sean Hussey is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2013/07/01/sean-hussey-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2013/07/01/sean-hussey-is-a-dockyarder</id>
    <category term="announcement" label="Announcement"/><category term="office" label="Office"/>
    <published>2013-07-01 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>We snag one of the tallest guys in Ruby</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/SNr5ZrZ.png&quot; alt=&quot;Sean Hussey&quot;&gt;
Today is the first day for Sean Hussey at DockYard. He has been
contracting with us for the past few months and I was finally able to
lock him down recently. Sean and I have known one another for years as
he hired me for my first Ruby job at
&lt;a href=&quot;http://global.rakuten.com/en/&quot;&gt;RakutenUSA&lt;/a&gt;. He brings years of Sr.
level Ruby experience to our team.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Introducing destroyed_at</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2013/06/28/introducing-destroyed_at" />
    <id>https://dockyard.com/blog/ruby/2013/06/28/introducing-destroyed_at</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="gems" label="Gems"/>
    <published>2013-06-28 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Michael Dupuis</name></author>
    <summary>An ActiveRecord mixin for safe destroys</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/dockyard/destroyed_at&quot;&gt;See the project on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We&amp;#39;ve found that more and more clients are requesting &amp;quot;undestroy&amp;quot;
functionality in their apps. We recently extracted this common pattern into a gem
we&amp;#39;re calling &lt;a href=&quot;https://github.com/dockyard/destroyed_at&quot;&gt;DestroyedAt&lt;/a&gt;, an ActiveRecord mixin that makes un-destroying records
simple.&lt;/p&gt;

&lt;p&gt;By
setting the datetime of the &lt;code&gt;#destroyed_at&lt;/code&gt; field of your record, you can
mark records as destroyed, without actually deleting them. By default, the
model in which you &lt;code&gt;include DestroyedAt&lt;/code&gt; is scoped to only include
records that have not been destroyed. So something like
&lt;code&gt;User.all&lt;/code&gt; will only return &lt;code&gt;User&lt;/code&gt;s with &lt;code&gt;#destroyed_at&lt;/code&gt; values of &lt;code&gt;nil&lt;/code&gt;;
and &lt;code&gt;User.unscoped.all&lt;/code&gt; will return all &lt;code&gt;User&lt;/code&gt; records.&lt;/p&gt;

&lt;p&gt;When you want to bring a
record back, simply call &lt;code&gt;#undestroy&lt;/code&gt; on the instance and its
&lt;code&gt;#destroyed_at&lt;/code&gt; will be set to &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ve baked a bunch of other functionality in as well, including
undestroy callbacks. For the full rundown, head over to &lt;a href=&quot;https://github.com/dockyard/destroyed_at&quot;&gt;DestroyedAt&amp;#39;s
GitHub page&lt;/a&gt; .&lt;/p&gt;
</content>
  </entry><entry>
    <title>Marin Abernethy is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2013/06/19/marin-abernethy-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2013/06/19/marin-abernethy-is-a-dockyarder</id>
    <category term="intern" label="Intern"/><category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2013-06-19 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Our first developer intern</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/SiT4FRr.jpg&quot; alt=&quot;Marin&quot;&gt;
Marin comes to us as from Trinity College for the summer. We&amp;#39;ve been
overwhelming her with Ruby, Linux, SQL, JavaScript, and VIM. She&amp;#39;s
excelled and we&amp;#39;re excited to see what she can accomplish over the
remainder of the summer.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Michael Dupuis is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2013/06/19/michael-dupuis-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2013/06/19/michael-dupuis-is-a-dockyarder</id>
    <category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2013-06-19 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Grow baby grow!</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/DctpNjW.jpg&quot; alt=&quot;Michael&quot;&gt;
Recently we added another great mind to the DockYard team: Michael
Dupuis. Mike joins our Boston office and has already been busy building
out client apps in Ruby on Rails and Ember.js for us! He also comes with
some design chops. Welcome Mike!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Context Validations</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2013/05/09/context-validations" />
    <id>https://dockyard.com/blog/ruby/2013/05/09/context-validations</id>
    <category term="gems" label="Gems"/><category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2013-05-09 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>An alternative to the normal Rails validations</summary>
    <content type="html">&lt;p&gt;I just released a new &lt;a href=&quot;https://github.com/dockyard/context_validations&quot;&gt;gem called ContextValidations&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ContextValidations allows you to set validations on the instance of
ActiveRecord models. Any class-level validations you have already set
in your models are ignored. You may be asking yourself &amp;quot;Whaaaaaat?&amp;quot; so
let&amp;#39;s look into why.&lt;/p&gt;

&lt;h2&gt;Conditional Validations Are A Smell&lt;/h2&gt;

&lt;p&gt;When applications grow in complexity the validation models required to
support them usually grow too. Eventually you will have to &amp;quot;work around&amp;quot;
the validations with conditionals that rely upon state flags. In some
cases you end up writing empty model objects for use with your forms to
avoid the mess that conditional validations introduce.&lt;/p&gt;

&lt;p&gt;The problem here is that the model is defining a single set of
validations but the model needs to absorb different sets of data under
different circumstances. Imagine you have a user account that where
depending upon how the users get to your app will depend upon what data
they need to provide. You might also be importing data from an external
incomplete data set. Do you set these records aside into another table
until the records are claimed and the user can complete registration? Or
do you allow the records to save and have the model enter a state of
&lt;code&gt;unclaimed&lt;/code&gt; to avoid authentication until &lt;code&gt;claimed&lt;/code&gt;? You could just
avoid the validations all together but you definitely don&amp;#39;t want to
allow records that don&amp;#39;t have the most basic of identifying information
such as &lt;code&gt;email&lt;/code&gt; or &lt;code&gt;username&lt;/code&gt; to be saved.&lt;/p&gt;

&lt;p&gt;You can imagine with this scenario the current solution with Rails is
either a very complex and messy validation model or breaking things out
into other models and having a strategy to reconciling that at a later
point in time.&lt;/p&gt;

&lt;h2&gt;Context Matters&lt;/h2&gt;

&lt;p&gt;I have come to believe that defining a monolithic validation set in your
model is the wrong way to go. Context matters. If I am an admin I should
be able to write data to a record that might not be acceptable to a
regular user. Even the simple case of not requiring a password unless
the record is new.&lt;/p&gt;

&lt;h3&gt;Controllers Are the Context&lt;/h3&gt;

&lt;p&gt;I believe the rule of &amp;quot;Fat Model, Skinny Controller&amp;quot; has conditioned
Rails developers to never ever put anything more than a few lines of
code into your controllers. For the most part this is a good trend. But
as we have seen with &lt;a href=&quot;https://github.com/rails/strong_parameters&quot;&gt;Strong Parameters&lt;/a&gt; 
there are circumstances where adding a few more lines to our controllers
isn&amp;#39;t going to end the world. I submit the case is also true for
validations. The controller is the context in which the user is
interacting with the data. Going back to the admin example, you most
likely have a &lt;code&gt;UsersController&lt;/code&gt; and an &lt;code&gt;Admin::UsersController&lt;/code&gt; defined.
Two controllers, same data. Different contexts. Not only should you
allow mass assignment to the models differently for each context but
what is considered &amp;quot;valid data&amp;quot; should also be different.&lt;/p&gt;

&lt;h2&gt;Context Validations&lt;/h2&gt;

&lt;p&gt;To handle this need I have just released
&lt;a href=&quot;https://github.com/dockyard/context_validations&quot;&gt;ContextValidations&lt;/a&gt;.
The goals of this gem are simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Maintain simplicity&lt;/li&gt;
&lt;li&gt;Enable instance level validations&lt;/li&gt;
&lt;li&gt;Don&amp;#39;t deviate from exisitng Rails validations&lt;/li&gt;
&lt;li&gt;Backwards compatibility with 3rd party libraries&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before I dive into each one let&amp;#39;s see how a set of validations might be
applied in a controller&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;UsersController&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ApplicationController&lt;/span&gt;
  include &lt;span class=&quot;constant&quot;&gt;ContextValidations&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Controller&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;create&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.new(user_params)
    &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.validations = validations(&lt;span class=&quot;symbol&quot;&gt;:create&lt;/span&gt;)
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.save
      &lt;span class=&quot;comment&quot;&gt;# happy path&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;comment&quot;&gt;# sad path&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;base_validations&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:first_name&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:last_name&lt;/span&gt; &lt;span class=&quot;symbol&quot;&gt;:email&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:presence&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:email&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:uniqueness&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:format&lt;/span&gt; =&amp;gt; &lt;span class=&quot;constant&quot;&gt;EmailFormat&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:confirmation&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;create_validations&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:presence&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Maintain Simplicity&lt;/h3&gt;

&lt;p&gt;At this point some of you are probably thinking &lt;a href=&quot;http://rhnh.net/2012/12/03/form-objects-in-rails&quot;&gt;Form Objects&lt;/a&gt;.
Perhaps in the end, Form Objects will be the real answer for what I
strive for. But right now I don&amp;#39;t see a justification for the increase
in complexity. &lt;code&gt;ContextValidations&lt;/code&gt; has attempted to keep the complexity
as low as possible while still allowing for flexibility. The
&lt;code&gt;ContextValidations::Controller&lt;/code&gt; module can be mixed into any object,
not just controllers. Let&amp;#39;s say you had a &lt;a href=&quot;http://stevelorek.com/service-objects.html&quot;&gt;Service Object&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;UserService&lt;/span&gt;
  include &lt;span class=&quot;constant&quot;&gt;ContextValidations&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Controller&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(params)
    &lt;span class=&quot;instance-variable&quot;&gt;@params&lt;/span&gt; = params
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;create&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.new(create_params)
    &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt; = validations(&lt;span class=&quot;symbol&quot;&gt;:create&lt;/span&gt;)
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;At this point the code looks identitly to the controller example from
above. The validations are accessible anywhere, from any object.&lt;/p&gt;

&lt;h3&gt;Instance level validations&lt;/h3&gt;

&lt;p&gt;The real key here is that the instance of the model is able to declare
what its validations are rather than the class. To that end you must
mixin the &lt;code&gt;ContextValidations::Model&lt;/code&gt; module into any model you want to
use &lt;code&gt;ContextValidations&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;User&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  include &lt;span class=&quot;constant&quot;&gt;ContextValidations&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Model&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This mixin will do several things to you &lt;code&gt;ActiveRecord&lt;/code&gt; model&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A &lt;code&gt;#validations&lt;/code&gt; setter and getter is added. The default for
&lt;code&gt;#validations&lt;/code&gt; is an empty array. When any arrays are assigned they are
wrapped in an array and falttened out.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;:validate&lt;/code&gt; callbacks are completed removed. This allows the
model to accept validations set on the class by 3rd party libraries but
these validations will never run.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;#run_validations!&lt;/code&gt; protected method is overwritten to run
through the instance level validations instead of running the
&lt;code&gt;:validate&lt;/code&gt; callback.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Don&amp;#39;t deviate from exisitng Rails validations&lt;/h3&gt;

&lt;p&gt;The only difference from writing your validations now is they are
written on the instance. The &lt;code&gt;#validates&lt;/code&gt; method functions exactly the
same way. You can still pass conditional validations if you&amp;#39;d like but I
wouldn&amp;#39;t recommend it.&lt;/p&gt;

&lt;h3&gt;Backwards compatibility with 3rd party libraries&lt;/h3&gt;

&lt;p&gt;As mentioned above we don&amp;#39;t want your Rails app to crash if 3rd party
libraries are declaring regular Rails validations in your models. They
are just ignored.&lt;/p&gt;

&lt;h2&gt;Moving forward&lt;/h2&gt;

&lt;p&gt;There are a few directions things could move in. I still haven&amp;#39;t come
up with a simple way to test &lt;code&gt;ContextValidations&lt;/code&gt;. There will also be
validations that are always used regardless of the context. I don&amp;#39;t
think it makes sense to constantly rewrite these validations. One
possibility would be to consider the class validations the
&lt;code&gt;base_validations&lt;/code&gt; that are always run then you can declare context
validations on the instance. This might cause issues with 3rd party
libraries that are using conditional validations. But, we could easily
get around that by ignoring any class level validations that have
conditionals on them.&lt;/p&gt;

&lt;p&gt;I am eager to get feedback on this. I am sure this might cause some
friction as it moves outside of the comfort zone for many Rails devs but
now I am happy with the direction.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Tilde&#39;s Ember Training</title>
    <link rel="alternate" href="https://dockyard.com/blog/ember/2013/05/09/tildes-ember-training" />
    <id>https://dockyard.com/blog/ember/2013/05/09/tildes-ember-training</id>
    <category term="ember" label="Ember.js"/><category term="training" label="Training"/>
    <published>2013-05-09 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>We sent a group of developers to the Ember.js training that Tilde taught at Bocoup Loft</summary>
    <content type="html">&lt;p&gt;A couple weeks ago, Yehuda Katz and Tom Dale of &lt;a href=&quot;http://tilde.io&quot;&gt;Tilde&lt;/a&gt; ran
their 3-day &lt;a href=&quot;http://www.tilde.io/training/&quot;&gt;Introduction to Ember.js Training&lt;/a&gt;
at &lt;a href=&quot;http://bocoup.com/&quot;&gt;Bocoup&lt;/a&gt; here in Boston. I, along with Amanda,
Doug and Chris, attended the training.&lt;/p&gt;

&lt;h2&gt;Format&lt;/h2&gt;

&lt;p&gt;Throughout the training, attendees were building a simplified Rdio/Spotify clone
using Ember. It was broken up into a series of exercises, which built
upon each other. The exercises were test driven, each having set of QUnit tests that defined the
exercise. Before each exercise, Tom and Yehuda would explain and demo
the concepts via slides and JSBin.&lt;/p&gt;

&lt;h3&gt;Day 1&lt;/h3&gt;

&lt;p&gt;Day 1 was spent outlining the core concepts of
&lt;a href=&quot;http://handlebarsjs.com&quot;&gt;Handlebars&lt;/a&gt; and Ember. We
started with Handlebars, which is what Ember uses as its templating
language. After covering the basics of Handlebars, we learned about how
&lt;a href=&quot;http://emberjs.com/guides/routing/&quot;&gt;Ember handles routing and outlets&lt;/a&gt;.
After we finished routing, we moved onto creating Handlebars helper
functions.&lt;/p&gt;

&lt;h3&gt;Day 2&lt;/h3&gt;

&lt;p&gt;On day 2, we started off with
&lt;a href=&quot;http://emberjs.com/guides/controllers/&quot;&gt;Ember controllers&lt;/a&gt; and how they
serve as proxy objects for the model of your current resource. After
controllers, we covered
&lt;a href=&quot;http://emberjs.com/guides/object-model/computed-properties/&quot;&gt;computed properties&lt;/a&gt;.
&lt;a href=&quot;http://emberjs.com/guides/views/&quot;&gt;Views&lt;/a&gt; followed computed properties,
then we wrapped up the day with creating custom controls with Ember and
Handlebars.&lt;/p&gt;

&lt;h3&gt;Day 3&lt;/h3&gt;

&lt;p&gt;Once we had built the majority of the app, we had a couple more
exercises that built upon all the exercise we had completed. Tom and
Yehuda also went over how we would use
&lt;a href=&quot;http://eviltrout.com/2013/03/23/ember-without-data.html&quot;&gt;Ajax requests to pull in data from a remote source with Promises&lt;/a&gt;.
After wrapping up the remainder of the exercises, we covered how the
&lt;a href=&quot;http://stackoverflow.com/questions/13597869/what-is-ember-runloop-and-how-does-it-work&quot;&gt;Ember Run Loop works&lt;/a&gt;,
and discussed approaches to testing Ember applications.&lt;/p&gt;

&lt;h2&gt;Feedback&lt;/h2&gt;

&lt;p&gt;Yehuda and Tom provided a great balance of not-to-dense information,
useful demos and exercises. They did a great job of, what Tom stated as,
&amp;quot;Providing a sufficient level of confusion&amp;quot; in the exercises. Before
each exercise, they would provide all the information needed for the
exercise, but would not give you a list of steps to complete the task.
You may struggle a bit, but they answer any questions you would
have during the exercise. This would help the attendees actually learn
the concepts, rather than just copy/paste a set of code and modify it
here and there and have it work. I, personally, felt that this worked
really well.&lt;/p&gt;

&lt;p&gt;I have worked on a couple side project with Ember before taking this
training, and had a very shallow understanding of some of the concepts.
Coming out of this training, I feel I have a great place to start building
Ember apps. I really fleshed out my understanding of Ember and am really
excited about the technology. I am planning on using it for
any upcoming side projects, to really explore it further. &lt;/p&gt;
</content>
  </entry><entry>
    <title>We are hiring for a fulltime Ember.js developer</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2013/04/04/we-are-hiring-for-an-emberjs-dev" />
    <id>https://dockyard.com/blog/ruby/2013/04/04/we-are-hiring-for-an-emberjs-dev</id>
    <category term="javascript" label="JavaScript"/><category term="office" label="Office"/><category term="jobs" label="Jobs"/><category term="ruby" label="Ruby"/><category term="ember" label="Ember.js"/>
    <published>2013-04-04 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Work at DockYard building Ember.js apps!</summary>
    <content type="html">&lt;p&gt;We are looking for an Ember.js Developer. Our ideal
candidate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work on cutting-edge Ember.js applications&lt;/li&gt;
&lt;li&gt;Passionate about new HTML/JavaScript technologies&lt;/li&gt;
&lt;li&gt;Has experience building complex client side applications&lt;/li&gt;
&lt;li&gt;Some backend experience would be nice&lt;/li&gt;
&lt;li&gt;Some database experience would be nice&lt;/li&gt;
&lt;li&gt;Enjoys contributing to open source, writing blog posts, giving talks&lt;/li&gt;
&lt;li&gt;Willing to live in Boston (we can relocate for the right candidate)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our current tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://rubyonrails.org&quot;&gt;Ruby on Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://emberjs.com&quot;&gt;Ember.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://postgresql.com&quot;&gt;PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://coffeescript.org&quot;&gt;CoffeeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Most of our apps deploy to &lt;a href=&quot;http://heroku.com&quot;&gt;Heroku&lt;/a&gt;, if not then
to &lt;a href=&quot;http://linode.com&quot;&gt;Linode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://dockyard.com&quot;&gt;DockYard&lt;/a&gt; is a Boston-based consultancy that always wants to work with
the best people and the best technology. We are committed to Ember.js as
a client side framework. We help organize the Boston &lt;a href=&quot;http://www.meetup.com/Boston-Ember-js&quot;&gt;Ember.js
meetup&lt;/a&gt; and
I recently spoke at &lt;a href=&quot;http://embercamp.com&quot;&gt;Ember Camp in San Francisco&lt;/a&gt;. We are already &lt;a href=&quot;https://github.com/dockyard/ember-builds&quot;&gt;building
tools around Ember.js&lt;/a&gt; and hope to continue to improve and build new ones
in the upcoming years.&lt;/p&gt;

&lt;p&gt;Please email &lt;a href=&quot;mailto:contact@dockyard.com&quot;&gt;contact@dockyard.com&lt;/a&gt; with
all relevant information on why you would be an ideal candidate for a
fulltime Ember.js developer.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Running PostgreSQL 9.2 on Travis-CI</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2013/03/29/running-postgresql-9-2-on-travis-ci" />
    <id>https://dockyard.com/blog/ruby/2013/03/29/running-postgresql-9-2-on-travis-ci</id>
    <category term="ruby" label="Ruby"/><category term="postgresql" label="PostgreSQL"/>
    <published>2013-03-29 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Test your gem against the latest PostgreSQL version (or an older one)</summary>
    <content type="html">&lt;p&gt;I spent most of yesterday trying to get PostgreSQL 9.2 running &lt;a href=&quot;http://travis-ci.org&quot;&gt;Travis-CI&lt;/a&gt;.
After almost 30 attempts, I successfully tested &lt;a href=&quot;https://github.com/dockyard/postgres_ext&quot;&gt;postgres_ext&lt;/a&gt; against PostgreSQL 9.2.&lt;/p&gt;

&lt;p&gt;Here is the final &lt;code&gt;before_script&lt;/code&gt; needed to install PostgreSQL 9.2.&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;before_script:
  - sudo /etc/init.d/postgresql stop
  - sudo cp /etc/postgresql/9.1/main/pg_hba.conf ./
  - sudo apt-get remove postgresql postgresql-9.1 -qq --purge
  - source /etc/lsb-release
  - echo &amp;quot;deb http://apt.postgresql.org/pub/repos/apt/ $DISTRIB_CODENAME-pgdg main&amp;quot; &amp;gt; pgdg.list
  - sudo mv pgdg.list /etc/apt/sources.list.d/
  - wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
  - sudo apt-get update
  - sudo apt-get -o Dpkg::Options::=&amp;quot;--force-confdef&amp;quot; -o Dpkg::Options::=&amp;quot;--force-confnew&amp;quot; install postgresql-9.2 postgresql-contrib-9.2 -qq
  - sudo /etc/init.d/postgresql stop
  - sudo cp ./pg_hba.conf /etc/postgresql/9.2/main
  - sudo /etc/init.d/postgresql start
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Step by step explanation&lt;/h2&gt;

&lt;h3&gt;Out with the old&lt;/h3&gt;

&lt;p&gt;Currently, Travis-CI has PostgreSQL 9.1 installed with a passwordless &lt;code&gt;postgres&lt;/code&gt; superuser role. We first stop the current user by calling
&lt;code&gt;sudo /etc/init.d/postgresql stop&lt;/code&gt;. We also want to copy the current &lt;code&gt;pg_hba.conf&lt;/code&gt;, since we can reuse it with PostgreSQL 9.2 to disable the need
for a password for the &lt;code&gt;postgres&lt;/code&gt; role. We then remove the currently installed version via &lt;code&gt;sudo apt-get remove postgresql postgresql-9.1 -qq --purge&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Add the apt.postgresql.org repositories&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://postgresql.org&quot;&gt;Postgresql.org&lt;/a&gt; maintains Debian and Ubuntu packages of the current PostgreSQL 8.3, 8.4, 9.0, 9.1 and 9.2 builds at
&lt;a href=&quot;http://apt.postgresql.org&quot;&gt;apt.postgresql.org&lt;/a&gt; (&lt;a href=&quot;https://wiki.postgresql.org/wiki/Apt&quot;&gt;more
information&lt;/a&gt;). Since Travis-CI
workers run Ubuntu, we can leverage these packages. We first load the
Ubuntu distribution environment variables via &lt;code&gt;source /etc/lsb-release&lt;/code&gt;.
Using the &lt;code&gt;$DISTRIB_CODENAME&lt;/code&gt; variable, we can set up the pgdg.list file
that we will add to the apt-get sources list directory. We do so with
the following command:&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;echo &amp;quot;deb http://apt.postgresql.org/pub/repos/apt/ $DISTRIB_CODENAME-pgdg main&amp;quot; &amp;gt; pgdg.list
sudo mv pgdg.list /etc/apt/sources.list.d/
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The last thing we have to do before we can start installing the 9.2 is
to import postgresql.org&amp;#39;s apt key via&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;In with the new&lt;/h3&gt;

&lt;p&gt;After we update our package listing via &lt;code&gt;sudo apt-get update&lt;/code&gt;, we can
install &lt;code&gt;postgresql-9.2&lt;/code&gt; and &lt;code&gt;postgresql-contrib-9.2&lt;/code&gt; (needed for the
PostgreSQL extensions) via:&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;sudo apt-get -o Dpkg::Options::=&amp;quot;--force-confdef&amp;quot; -o Dpkg::Options::=&amp;quot;--force-confnew&amp;quot; install postgresql-9.2 postgresql-contrib-9.2 -qq
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We need the &lt;code&gt;Dpkg::Options&lt;/code&gt; to automatically resolve any configuration
file conflicts left behind by 9.1 (even though we purge the files, for
some reason the &lt;code&gt;/etc/init.d/postgresql&lt;/code&gt; file gets left behind). Without
the &lt;code&gt;Dpkg::Options&lt;/code&gt;, apt-get will raise a user prompt that will hang the
Travis-CI build.&lt;/p&gt;

&lt;p&gt;At this point, we have a vanilla install of PostgreSQL 9.2, which will
prompt for a password for the &lt;code&gt;postgres&lt;/code&gt; role. We then need to stop the
server, replace the 9.2 &lt;code&gt;pg_hba.conf&lt;/code&gt; with the custom Travis-CI one we
copied earlier, then restart the server:&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;sudo /etc/init.d/postgresql stop
sudo cp ./pg_hba.conf /etc/postgresql/9.2/main
sudo /etc/init.d/postgresql start
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;At this point, you can use any other &lt;code&gt;before_script&lt;/code&gt; commands you were
previously using to create your database.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;After a decent amount of trial and error, I arrived at the above
&lt;code&gt;before_script&lt;/code&gt; to install PostgreSQL 9.2. I am currently adding support
for &lt;a href=&quot;http://www.postgresql.org/docs/9.2/static/rangetypes.html&quot;&gt;ranges&lt;/a&gt;
to postgres&lt;em&gt;ext, which was added in 9.2. You should be able use this
`before&lt;/em&gt;script` to add 9.2 to your Travis-CI builds.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Adding route specific body class tags in Ember</title>
    <link rel="alternate" href="https://dockyard.com/blog/ember/2013/03/27/body-class-tags-in-ember" />
    <id>https://dockyard.com/blog/ember/2013/03/27/body-class-tags-in-ember</id>
    <category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/><category term="design" label="Design"/>
    <published>2013-03-27 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>For design!</summary>
    <content type="html">&lt;p&gt;Our &lt;a href=&quot;http://twitter.com/cssboy&quot;&gt;designer&lt;/a&gt; likes to use body class tags
depending upon the context of the app he is designing. We&amp;#39;re currently
building an Ember app and this is how I got it working:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;Ember.Route.reopen({
  &lt;span class=&quot;function&quot;&gt;activate&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; cssClass = &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.toCssClass();
    &lt;span class=&quot;comment&quot;&gt;// you probably don&#39;t need the application class&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// to be added to the body&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (cssClass != &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) {
      Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).addClass(cssClass);
    }
  },
  &lt;span class=&quot;function&quot;&gt;deactivate&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    Ember.&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).removeClass(&lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.toCssClass());
  },
  &lt;span class=&quot;function&quot;&gt;toCssClass&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;local-variable&quot;&gt;this&lt;/span&gt;.routeName.replace(&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;modifier&quot;&gt;g&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).dasherize();
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;</content>
  </entry><entry>
    <title>Concurrent Indexes in PostgreSQL for Rails 4 and Postgres_ext</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2013/03/26/concurrent-indexes-in-postgresql-for-rails-4-and-postgres_ext" />
    <id>https://dockyard.com/blog/ruby/2013/03/26/concurrent-indexes-in-postgresql-for-rails-4-and-postgres_ext</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/><category term="postgresql" label="PostgreSQL"/>
    <published>2013-03-26 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Prevent new indexes from locking up your tables</summary>
    <content type="html">&lt;p&gt;PostgreSQL allows you to &lt;a href=&quot;http://www.postgresguide.com/performance/indexes.html#create-index-concurrently&quot;&gt;create your indexes
concurrently&lt;/a&gt;
so that your table isn&amp;#39;t locked as the index builds. This allows you to
avoid taking a performance hit when adding a new index to a large table.
Yesterday, I submitted a &lt;a href=&quot;https://github.com/rails/rails/pull/9923&quot;&gt;pull request to
Rails&lt;/a&gt; that as merged in this
morning that allows you to add concurrent indexes through the
&lt;code&gt;add_index&lt;/code&gt; method in your migrations. To create an index concurrently,
you add the &lt;code&gt;algorithm: :concurrently&lt;/code&gt; option to the &lt;code&gt;add_index&lt;/code&gt; call&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;add_index &lt;span class=&quot;symbol&quot;&gt;:table&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:column&lt;/span&gt;, &lt;span class=&quot;key&quot;&gt;algorithm&lt;/span&gt;: &lt;span class=&quot;symbol&quot;&gt;:concurrently&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A side effect of this commit is that it also enables the &lt;code&gt;algorithm&lt;/code&gt;
option for MySQL too, so MySQL users can create indexes using &lt;code&gt;DEFAULT&lt;/code&gt;,
&lt;code&gt;INPLACE&lt;/code&gt; or &lt;code&gt;COPY&lt;/code&gt; algorithm when creating indexes.&lt;/p&gt;

&lt;h2&gt;Postgres_ext gains concurrent index support as well&lt;/h2&gt;

&lt;p&gt;This morning I added support for concurrent indexes to
&lt;a href=&quot;https://github.com/dockyard/postgres_ext&quot;&gt;postgres_ext&lt;/a&gt; as well, using
the same syntax as the Rails 4 example above. The 0.3.0 version of
postgres_ext was released, which contains this, and a &lt;a href=&quot;https://github.com/dockyard/postgres_ext/blob/master/CHANGELOG.md#030&quot;&gt;slew of other
improvements as
well&lt;/a&gt;.
One thing to note, the &lt;code&gt;index_type&lt;/code&gt; option for &lt;code&gt;add_index&lt;/code&gt; has been
renamed to &lt;code&gt;using&lt;/code&gt; to match Rails 4.&lt;/p&gt;

&lt;p&gt;If you have any features you want to see in postgres_ext or have any
issues, &lt;a href=&quot;https://github.com/dockyard/postgres_ext/issue&quot;&gt;open an issue&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Igata</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2013/03/25/igata" />
    <id>https://dockyard.com/blog/ruby/2013/03/25/igata</id>
    <category term="ruby" label="Ruby"/><category term="business" label="Business"/><category term="products" label="Products"/>
    <published>2013-03-25 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>We built an App Store for Heroku, got bored with it, and now open sourced it</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/dockyard/igata&quot;&gt;View the code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://igata.io&quot;&gt;Try it out!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A year and a half ago I started thinking about a product I wanted to
build. I am a big fan of Heroku and I felt something missing from their
eco-system was an App Store. Similar to the WordPress Theme Store. This
Heroku App Store would allow developers to create fully realized
applications and sell them to non developers. The person on the
purchasing side wouldn&amp;#39;t even need to know about Heroku. We built this
product over the past year, got the &amp;quot;thumbs up&amp;quot; from Heroku, finally got bored with the idea of launching it, and
are now open sourcing it for all to see. I will go into the challenges we
faced as a consulting firm building a product and why we decided to give
this away rather than &amp;quot;go for it&amp;quot;.&lt;/p&gt;

&lt;h2&gt;Concept to reality&lt;/h2&gt;

&lt;p&gt;The concept was simple: App Store for Heroku. I built the original app
code in May of 2012. I would say about 50% of the app was completed in a
week. However, what I quickly learned is that balancing consulting a
product development is not easy. Quickly development on Igata turned
into a see-saw. A day of work here and there in between contracts. It
became very difficult to stay focused and keep interested in the
project. But I believed it was one that could do well if positioned
properly. The idea of proving an additional revenue stream to Heroku
also felt like a good challenge.&lt;/p&gt;

&lt;p&gt;I let the app sit for a few months while we were working on a very large
contract over the summer. Then the Rails Rumble came and I was a judge,
I saw an app called &lt;a href=&quot;https://deploybutton.com&quot;&gt;Deploy Button&lt;/a&gt; and I
freaked out. This was essentially what we had already built but without
the purchasing aspect. I emailed my team and told them we weren&amp;#39;t taking
any more contracts until we finished Igata. This proved to not work very
well in reality. As a Rails consultancy we are not cheap but you don&amp;#39;t
realize just how expensive you are until there is no money coming in. So
we went back on contract and shelved Igata, again. I kept coming back to
it every so often. Finally I decided to open source it.&lt;/p&gt;

&lt;h2&gt;Validation&lt;/h2&gt;

&lt;p&gt;It wasn&amp;#39;t until I made the decision to open source Igata that I started
to get some validation of the concept. I was very secretive about the
app as I figured if Heroku found out about it, and liked the idea, they
would just toss a few devs at it for a week or two and come out with an
&amp;quot;official&amp;quot; app store. But now that I was going to OSS is fuck it, I&amp;#39;ll
tell everybody! I told a few friends that work at Heroku and in the end
it was foolish of me to worry about that sort of thing. Several people
encouraged me not to open source and just finish and release. So I went
to Waza (Heroku&amp;#39;s Conference) and met with a few people from Heroku&amp;#39;s
Partner program, once I showed them the app they loved it.&lt;/p&gt;

&lt;p&gt;I came home a few weeks ago, pumped to finish the app.&lt;/p&gt;

&lt;h2&gt;Back to Open Sourcing&lt;/h2&gt;

&lt;p&gt;I wouldn&amp;#39;t say doubt began to creep back in, just more that I really
didn&amp;#39;t like the idea of what would come of Heroku if it it was a
success. Maintaining an app store and building it out really doesn&amp;#39;t
interest me at all. I had a choice: shit or get off the pot. I&amp;#39;ve now
decided to get off the pot.&lt;/p&gt;

&lt;p&gt;I&amp;#39;m happy to go into more details on what our business model would have
been in another post if people are interested. The app itself is about
95% complete. There were some changes to the payment system we would
make. But overall I&amp;#39;m happy with what we built considering the very
disrupted development schedule on it. I hope this app can serve someone
well.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Fixing Capybara 2.0 and Labels</title>
    <link rel="alternate" href="https://dockyard.com/blog/ember/2013/03/21/capybara-and-unique-labels" />
    <id>https://dockyard.com/blog/ember/2013/03/21/capybara-and-unique-labels</id>
    <category term="testing" label="Testing"/><category term="ember" label="Ember.js"/>
    <published>2013-03-21 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Capybara is broken, they refused to fix. Here is the monkey patch</summary>
    <content type="html">&lt;p&gt;I love Capybara, it makes integration testing a breeze. However, one of
the decisions made for Capybara 2.0 confuses an annoys me. In Capybara
1.x you could do the following:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;fill_in &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Password&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:with&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;123456&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
fill_in &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Password confirmation&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:with&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;123456&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And everything worked. In Capybara 2.0 this does not work. Capybara will
notice two labels that contain &amp;#39;Password&amp;#39; and complain about an
ambiguous locator. The suggested work around is to attach meta data to
the input element and use that for the selector. There are two reasons
why I don&amp;#39;t like this. First, I am doing Ember development now and I
have no control of the ID, it is generated by the framework. Second, I
believe that the integration test should be recreating the steps (as
much as possible) as if a user were actually using the app. Something
like:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;fill_in &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[data-name=&amp;quot;password&amp;quot;]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:with&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;123456&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
fill_in &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[data-name=&amp;quot;password_confirmation&amp;quot;]&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:with&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;123456&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Doesn&amp;#39;t sit right with me. Users are looking at the text, not the selectors.
I get that apps have the ability to show different languages but that doesn&amp;#39;t conern me, I don&amp;#39;t need
to test if the Rails &lt;code&gt;i18n&lt;/code&gt; works or not. I just care about asserting the happy and sad
paths in my app.&lt;/p&gt;

&lt;p&gt;So, to fix this problem simply add the
following code into your &lt;code&gt;test_helper.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;XPath::HTML&lt;/span&gt;
  protected

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;locate_field&lt;/span&gt;(xpath, locator)
    locate_field = xpath[attr(&lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;).equals(locator) | attr(&lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;).equals(locator) | attr(&lt;span class=&quot;symbol&quot;&gt;:placeholder&lt;/span&gt;).equals(locator) | attr(&lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;).equals(anywhere(&lt;span class=&quot;symbol&quot;&gt;:label&lt;/span&gt;)[string.n.equals(locator)].attr(&lt;span class=&quot;symbol&quot;&gt;:for&lt;/span&gt;))]
    locate_field += descendant(&lt;span class=&quot;symbol&quot;&gt;:label&lt;/span&gt;)[string.n.contains(locator)].descendant(xpath)
    locate_field[~attr(&lt;span class=&quot;symbol&quot;&gt;:disabled&lt;/span&gt;)]
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And you should be all set!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Mike Sager Joins DockYard</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2013/03/19/mike-sager-joins-dockyard" />
    <id>https://dockyard.com/blog/announcement/2013/03/19/mike-sager-joins-dockyard</id>
    <category term="announcement" label="Announcement"/><category term="office" label="Office"/>
    <published>2013-03-19 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Sager!!!!!</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/dtyb8Zg.png&quot; alt=&quot;Sager&quot;&gt;&lt;/p&gt;

&lt;p&gt;I&amp;#39;m very happy to announce that Mike Sager has joined DockYard! Sager
and I met while working on The Campaign That Shall Not Be Named (it was
a very &amp;quot;special&amp;quot; one in MA) we kept in touch on and off after that until
we recently worked together on a project for the AFL-CIO.&lt;/p&gt;

&lt;p&gt;Sager brings an intimate knowledge of the progressive political tech
arena. DockYard is already making a great name for itself with political
tech and NPOs and we&amp;#39;re looking forward to the klout that Sager will
bring to the table.&lt;/p&gt;

&lt;p&gt;While not yet &amp;quot;official&amp;quot; we will soon be opening an office in
Washington, DC. Sager and Chris Gill will be running this office and we
are looking to hire Rails developers that have experience building apps
in politics. &lt;a href=&quot;mailto:contact@dockyard.com&quot;&gt;Join us!&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Introducing Ember-EasyForm</title>
    <link rel="alternate" href="https://dockyard.com/blog/ember/2013/02/21/ember-easy-form" />
    <id>https://dockyard.com/blog/ember/2013/02/21/ember-easy-form</id>
    <category term="javascript" label="JavaScript"/><category term="ember" label="Ember.js"/><category term="ember-libraries" label="Ember Libraries"/>
    <published>2013-02-21 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A SimpleForm-like FormBuilder for Ember</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/dockyard/ember-easyForm&quot;&gt;View the project on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the more tedious tasks in Ember is writing forms. It is not
uncommon to have to write something like so:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;input string&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstNameField.field_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;First name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstNameField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;input string&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastNameField.field_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Last name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastNameField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;input string&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ageField.field_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Age&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ageField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;value&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Submit&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And this is just a very simple form, but what if we could write this:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;formFor&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;formFor&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That is &lt;em&gt;much&lt;/em&gt; more concise! We pass the &lt;code&gt;controller&lt;/code&gt; as the context to
the &lt;code&gt;formFor&lt;/code&gt; Handlebars helper. Then we can simply call &lt;code&gt;input&lt;/code&gt; for
each property we want.&lt;/p&gt;

&lt;p&gt;By default &lt;code&gt;EasyForm&lt;/code&gt; will use text fields for the rendered input.
However, in certain cases it will attempt to properly set the &lt;code&gt;type&lt;/code&gt;. If
the property contains &lt;code&gt;email&lt;/code&gt; the &lt;code&gt;type&lt;/code&gt; will be set to &lt;code&gt;email&lt;/code&gt; or of
the property contains &lt;code&gt;password&lt;/code&gt; the &lt;code&gt;type&lt;/code&gt; will be set to &lt;code&gt;password&lt;/code&gt;.
You can override this and set the type yourself:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Currently the only other input type supported is &lt;code&gt;textarea&lt;/code&gt;, you can
create one with:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;bio&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;as&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I plan on adding support for the other input types such as &lt;code&gt;select&lt;/code&gt; in
the next few weeks.&lt;/p&gt;

&lt;h2&gt;Validations&lt;/h2&gt;

&lt;p&gt;This implementation has basic support for property validations.
Currently it works with &lt;code&gt;ember-data-validations&lt;/code&gt; but that project might
get rolled into a larger Ember Object Validation effort and at that time
I will change &lt;code&gt;ember-easyForm&lt;/code&gt; to support whatever that is.&lt;/p&gt;

&lt;p&gt;Validations will fire on &lt;code&gt;onFocusOut&lt;/code&gt; for each input and will render
into a &lt;code&gt;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;&lt;/code&gt; element associated with the given input.&lt;/p&gt;

&lt;p&gt;If your model doesn&amp;#39;t have validations this behavior will be ignored.&lt;/p&gt;

&lt;h2&gt;Form Submit&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;submit&lt;/code&gt; helper will render a submit input but you can just write
one yourself if you wish. The &lt;code&gt;onSubmit&lt;/code&gt; action for the wrapping &lt;code&gt;form&lt;/code&gt;
element will do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Attempt to validate for object. If validations are not supported it
will go to step 3.&lt;/li&gt;
&lt;li&gt;If validations fail form submit is interrupted and errors are
rendered. If not go to step 3.&lt;/li&gt;
&lt;li&gt;The view for the &lt;code&gt;form&lt;/code&gt; element will attempt to call a &lt;code&gt;submit&lt;/code&gt;
action on the controller. This is an action that you need to supply
yourself:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.NewUserController = Ember.ObjectController.extend({
  &lt;span class=&quot;function&quot;&gt;submit&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;() {
    &lt;span class=&quot;comment&quot;&gt;// handle form submit here&lt;/span&gt;
  }
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;More to come!&lt;/h2&gt;

&lt;p&gt;This is very close to what I recently (and briefly) showed at
&lt;a href=&quot;http://www.embercamp.com&quot;&gt;EmberCamp&lt;/a&gt;
last week. I hope to continue to build this project into a form builder
that evrerybody will be happy to use. &lt;a href=&quot;https://github.com/dockyard/ember-easyForm/issues&quot;&gt;Please feel free to propose new
idea in the issues for this project on GitHub&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building an Ember app with RailsAPI - Part 3</title>
    <link rel="alternate" href="https://dockyard.com/blog/ember/2013/01/10/building-an-ember-app-with-rails-api-part-3" />
    <id>https://dockyard.com/blog/ember/2013/01/10/building-an-ember-app-with-rails-api-part-3</id>
    <category term="javascript" label="JavaScript"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="ember" label="Ember.js"/>
    <published>2013-01-10 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>CUD, it isn&#39;t just for cows</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article was last updated on May 28, 2013 and reflects the state
 of Ember (1.0.0-rc4) and the latest build of Ember Data (0.13) as of
that date.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bcardarella/ember-railsapi&quot;&gt;Fork the project on Github!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://ember-rails-api.herokuapp.com/&quot;&gt;Use the app live on Heroku&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;/ember/2013/01/07/building-an-ember-app-with-rails-api-part-1.html&quot;&gt;Part 1&lt;/a&gt; I showed you how to setup a &lt;code&gt;Rails-API&lt;/code&gt; app for Ember.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;/ember/2013/01/09/building-an-ember-app-with-rails-api-part-2.html&quot;&gt;Part 2&lt;/a&gt; I showed you the basics of building an Ember app, reading from a backend API and displaying that information.&lt;/p&gt;

&lt;p&gt;Today we&amp;#39;re going to do some coding on the Rails side and the Ember side to add Creating, Updating, and Destroying records.&lt;/p&gt;

&lt;h2&gt;Part 3 - The Big Finish&lt;/h2&gt;

&lt;p&gt;In &lt;a href=&quot;http://reefpoints.dockyard.com/ember/2013/01/07/building-an-ember-app-with-rails-api-part-1.html&quot;&gt;Part 1&lt;/a&gt; we setup the backend using &lt;a href=&quot;https://github.com/rails-api/rails-api/&quot;&gt;Rails API&lt;/a&gt;. In &lt;a href=&quot;http://reefpoints.dockyard.com/ember/2013/01/09/building-an-ember-app-with-rails-api-part-2.html&quot;&gt;Part 2&lt;/a&gt; we built out the basics of an Ember app, reading from a remote data source and displaying that data. Now we&amp;#39;re going to add the ability to Create, Update, and Destroy that data. This part will be a mix of Ember and Rails code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: If you have been following along that &lt;a href=&quot;http://reefpoints.dockyard.com/ember/2013/01/09/building-an-ember-app-with-rails-api-part-2.html&quot;&gt;Part 2&lt;/a&gt; was recently updated to reflect new changes to the Ember Router, you will need to go back and update your code. Absolute make sure to update your ember.js and ember-data.js dependencies as they have been updated on the github repo&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Create&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s start by adding a &lt;code&gt;Create&lt;/code&gt; button to our index page:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;users.new&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-primary&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;Create&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We need to add the proper route so the index page doesn&amp;#39;t blow up. While we&amp;#39;re in here we&amp;#39;ll add the &lt;code&gt;edit&lt;/code&gt; route as well.&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Router.map -&amp;gt;
  @resource &#39;users&#39;, -&amp;gt;
    @route &#39;new&#39;
    @route &#39;edit&#39;,
      path: &#39;/:user_id/edit&#39;
    @route &#39;show&#39;,
      path: &#39;/:user_id&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And now we can add the &lt;code&gt;UsersNewRoute&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.UsersNewRoute = App.UsersRoute.extend
  model: -&amp;gt;
    App.User.createRecord()
  setupController: (controller, model) -&amp;gt;
    controller.set(&#39;content&#39;, model)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Don&amp;#39;t be fooled by the &lt;code&gt;createRecord()&lt;/code&gt; call. This will not write anything to the backend. This call is simply used to create a new model. Now let&amp;#39;s create the template &lt;code&gt;app/assets/javascripts/templates/users/new.hbs&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Create &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstNameField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstNameField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastNameField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Last Name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastNameField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quoteField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Quote&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextArea&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quoteField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-success&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Create&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;page-header&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;cancel&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-inverse&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next we&amp;#39;ll add &lt;code&gt;app/assets/javascripts/controllers/users/newController.coffeescript&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.UsersNewController = Ember.ObjectController.extend
  headerTitle: &#39;Create&#39;
  buttonTitle: &#39;Create&#39;

  save: -&amp;gt;
    @content.save().then =&amp;gt;
      @transitionToRoute(&#39;users.show&#39;, @content)

  cancel: -&amp;gt;
    @content.deleteRecord()
    @transitionToRoute(&#39;users.index&#39;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first two functions &lt;code&gt;save&lt;/code&gt; and &lt;code&gt;cancel&lt;/code&gt; are actions that are mapped in the template. Let&amp;#39;s break down each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;save&lt;/code&gt; will make a call to &lt;code&gt;this.store.commit()&lt;/code&gt;. You will notice we are not modifying a model, assigning params, etc... as you would in a Rails app. Keep in mind that when you modify data that is bound in the form you are actually modifying the data in the model itself. The datastore in Ember needs to be directed when these modifications should be made &amp;quot;permanent&amp;quot;, and because we are using the RESTAdapter Ember will attempt to write these changes to the backend.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancel&lt;/code&gt; If the user decides to not create a new user we must delete the record we created then transition to the &lt;code&gt;index&lt;/code&gt; page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;http://emberjs.com/guides/models/model-lifecycle&quot;&gt;Learn more about the Ember Model Lifecycle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally we&amp;#39;re going to hook up the back end in &lt;code&gt;app/controllers/users_controller.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;create&lt;/span&gt;
  user = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.new(params[&lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt;])

  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; user.save
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: user
  &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: user, &lt;span class=&quot;key&quot;&gt;status&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;422&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It has been mentioned that &lt;code&gt;422&lt;/code&gt; is the proper status code for validation failures. Personally I would prefer to use &lt;code&gt;respond_with&lt;/code&gt; but it isn&amp;#39;t part of the default Rails-API stack, &lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!topic/rails-api-core/QhPh2VG7yTU&quot;&gt;hopefully this will change&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now let&amp;#39;s run our app and see how it goes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/kFC9arb.png&quot; alt=&quot;New1&quot;&gt;&lt;/p&gt;

&lt;p&gt;Whoops, we have &lt;code&gt;undefined undefined&lt;/code&gt; for the &lt;code&gt;fullName&lt;/code&gt;. Let&amp;#39;s set default values of an empty string in our user model:&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.User = DS.Model.extend
  firstName: DS.attr(&#39;string&#39;, defaultValue: &#39;&#39; )
  lastName: DS.attr(&#39;string&#39;, defaultValue: &#39;&#39; )
  quote: DS.attr(&#39;string&#39;)
  fullName: (-&amp;gt;
    &amp;quot;#{@get(&#39;firstName&#39;)} #{@get(&#39;lastName&#39;)}&amp;quot;
  ).property(&#39;firstName&#39;, &#39;lastName&#39;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now when we add data and create it will write to the back end, take us to the show page. When can then click &lt;code&gt;Back&lt;/code&gt; and we can see the record has been automatically added to the collection on the &lt;code&gt;index&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;Adding &lt;code&gt;Edit&lt;/code&gt; should be straight forward now that we have done create. Start will adding the route:&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.UsersEditRoute = Ember.Route.extend
  model: (params) -&amp;gt;
    App.User.find(params.user_id)
  setupController: (controller, model) -&amp;gt;
    controller.set(&#39;content&#39;, model)
    @controllerFor(&#39;application&#39;).set(&#39;currentRoute&#39;, &#39;users&#39;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You&amp;#39;ll notice that this route is identical to &lt;code&gt;App.UsersShowRoute&lt;/code&gt; we wrote in Part 2, let&amp;#39;s DRY this up&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.UserRoute = Ember.Route.extend
  model: (params) -&amp;gt;
    App.User.find(params.user_id)
  setupController: (controller, model) -&amp;gt;
    controller.set(&#39;content&#39;, model)
    @controllerFor(&#39;application&#39;).set(&#39;currentRoute&#39;, &#39;users&#39;)

App.UsersShowRoute = App.UserRoute.extend()
App.UsersEditRoute = App.UserRoute.extend()
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next we&amp;#39;ll add the edit link to &lt;code&gt;app/assets/javascripts/templates/users/show.hbs&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;users.edit&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-primary&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;Edit&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now the edit template itself in &lt;code&gt;app/assets/javascripts/templates/users/edit.hbs&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Edit &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstNameField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstNameField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastNameField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Last Name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastNameField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quoteField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Quote&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextArea&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quoteField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-success&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Update&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;page-header&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;cancel&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;target&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-inverse&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And now the controller &lt;code&gt;app/assets/javascripts/controllers/users/editController.coffee&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.UsersEditController = Ember.ObjectController.extend
  destroy: -&amp;gt;
    @content.deleteRecord()
    @store.commit()
    @transitionTo(&#39;users.index&#39;)

  save: -&amp;gt;
    @content.save().then =&amp;gt;
      @transitionToRoute(&#39;users.show&#39;, @content)

  cancel: -&amp;gt;
    if @content.isDirty
      @content.rollback()
    @transitionTo(&#39;users.show&#39;, @content)

  buttonTitle: &#39;Edit&#39;
  headerTitle: &#39;Editing&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This controller looks similar to &lt;code&gt;App.UsersNewController&lt;/code&gt; but let&amp;#39;s explore the differences&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;save&lt;/code&gt; here because the model already has an &lt;code&gt;id&lt;/code&gt; we can commit to the datastore and transition.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cancel&lt;/code&gt; instead of deleting the record we want to rollback to its previous state. And we can only rollback if the record has changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&amp;#39;m sure you know what is next. The &lt;code&gt;new&lt;/code&gt; template is nearly identical to the &lt;code&gt;edit&lt;/code&gt; template. Let&amp;#39;s create &lt;code&gt;app/assets/javascripts/templates/users/form.hbs&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;headerTitle&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;form&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstNameField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;firstNameField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastNameField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Last Name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextField&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;lastNameField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quoteField.elementId&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Quote&lt;span class=&quot;tag&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;Ember.TextArea&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;valueBinding&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;viewName&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quoteField&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-success&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;buttonTitle&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;page-header&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;cancel&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;target&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-inverse&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And in both the &lt;code&gt;new&lt;/code&gt; and &lt;code&gt;edit&lt;/code&gt; template remove the markup and replace with&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt; &lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we need to edit the two controllers. In &lt;code&gt;App.UsersNewController&lt;/code&gt; add to the two attributes:&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;headerTitle: &#39;Create&#39;
buttonTitle: &#39;Create&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And likewise in &lt;code&gt;App.UsersEditController&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;headerTitle: &#39;Edit&#39;
buttonTitle: &#39;Update&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Last part for this section is to add the &lt;code&gt;update&lt;/code&gt; action to &lt;code&gt;app/controllers/users_controller.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;update&lt;/span&gt;
  user = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.find(params[&lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;])
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; user.update_attributes(params[&lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt;])
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: user
  &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: user, &lt;span class=&quot;key&quot;&gt;status&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;422&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now go through and everything should work! This allows us to treat the templates similar to a partial in Rails.&lt;/p&gt;

&lt;p&gt;Finally we&amp;#39;re going to add the ability to delete records. Because this is an action we are going to limit to the &lt;code&gt;edit&lt;/code&gt; page we will put the link below the &lt;code&gt;render&lt;/code&gt; call&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;href&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn btn-danger&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;Destroy&lt;span class=&quot;tag&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we add the action to the &lt;code&gt;App.UsersEditController&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;destroy: -&amp;gt;
  @content.deleteRecord()
  @store.commit()
  @transitionToRoute &#39;users.index&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And we add the &lt;code&gt;destroy&lt;/code&gt; action to the backend&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;destroy&lt;/span&gt;
  user = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.find(params[&lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;])
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; user.destroy
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: user, &lt;span class=&quot;key&quot;&gt;status&lt;/span&gt;: &lt;span class=&quot;integer&quot;&gt;204&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: user
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;204&lt;/code&gt; status here is refers to &lt;code&gt;No Content&lt;/code&gt;. Ember-data expects this to ensure the destroy action is a success.&lt;/p&gt;

&lt;p&gt;That&amp;#39;s it! You&amp;#39;ve just created your very first Ember app with all of the CRUD actions. Congratulations!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building an Ember app with RailsAPI - Part 2</title>
    <link rel="alternate" href="https://dockyard.com/blog/ember/2013/01/09/building-an-ember-app-with-rails-api-part-2" />
    <id>https://dockyard.com/blog/ember/2013/01/09/building-an-ember-app-with-rails-api-part-2</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/>
    <published>2013-01-09 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Building the Ember app</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article was last updated on May 28, 2013 and reflects the state
 of Ember (1.0.0-rc4) and the latest build of Ember Data (0.13) as of
that date.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bcardarella/ember-railsapi&quot;&gt;Fork the project on Github!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://ember-rails-api.herokuapp.com/&quot;&gt;Use the app live on Heroku&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;/ember/2013/01/07/building-an-ember-app-with-rails-api-part-1.html&quot;&gt;Part 1&lt;/a&gt; I showed you how to setup a &lt;code&gt;Rails-API&lt;/code&gt; app for Ember. Now let&amp;#39;s build the app itself.&lt;/p&gt;

&lt;p&gt;In this part I will go over building the Ember app from the perspective of a Rails developer. I will be making comparisons to where Ember resembles common patterns in Rails and even Ruby itself.&lt;/p&gt;

&lt;p&gt;I know I promised a 2-part series but I&amp;#39;m going to extend this to 3-parts. This post was growing too large to cover everything.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Note: this post has been updated since it was originally written. If
you were following along you should start from the beginning of this
post as changes have been made to reflect the changes on Ember&amp;#39;s master
branch! *&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Part 2 - Building with Ember&lt;/h2&gt;

&lt;p&gt;We need to start with something I forgot to setup in Part 1. Ember looks for templates in the &lt;code&gt;Ember.TEMPLATES&lt;/code&gt; JavaScript object which is provided to us with the &lt;code&gt;handlebars_assets&lt;/code&gt; gem we setup in Part 1. We just need to tell the gem to compile for Ember. We can do this in &lt;code&gt;config/initializers/handlebars_assets.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;defined?&lt;/span&gt;(&lt;span class=&quot;constant&quot;&gt;HandlebarsAssets&lt;/span&gt;)
  &lt;span class=&quot;constant&quot;&gt;HandlebarsAssets&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Config&lt;/span&gt;.ember = &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;NOTE:&lt;/em&gt; If you have skipped ahead and come back to this initializer you will need to run:&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;rm -rf tmp/*
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Otherwise your Ember templates won&amp;#39;t compile properly.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s dive in by creating our application layout template in &lt;code&gt;app/assets/javascripts/templates/application.hbs&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;navbar navbar-inverse navbar-fixed-top&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;navbar-inner&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;nav-collapse collapse&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;ul&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;nav&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;Home&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;tag&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;Users&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;id&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;span12&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;page-header&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;outlet&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://emberjs.com/guides/templates/handlebars-basics&quot;&gt;Read more about Ember Templates&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the Ember equivalent of a Rails layout template. The &lt;code&gt;outlet&lt;/code&gt; is the Ember equivalent to &lt;code&gt;yield&lt;/code&gt; in Rails. So this template will wrap the other templates we plan on rendering. I will come back to the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;s in the nav later.&lt;/p&gt;

&lt;p&gt;Next we&amp;#39;re going to setup a default route and render a template. In &lt;code&gt;app/assets/javascripts/routes.coffee&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Router.reopen
  location: &#39;history&#39;
  rootURL: &#39;/&#39;

App.Router.map -&amp;gt;
  @resource &#39;users&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://emberjs.com/guides/routing&quot;&gt;Read more about Ember Routes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will tell the Ember Router to use the History API instead of the
default &amp;#39;hash&amp;#39; URLs for routes. The mapping of the &lt;code&gt;/&lt;/code&gt; in our app is
implicit in Ember, and it will be assigned to a route of 
&lt;code&gt;index&lt;/code&gt;. The Ember Router will use this string to make some
assumptions. If there is a &lt;code&gt;App.IndexController&lt;/code&gt; object it will use that
controller. If not, it will just render out the &lt;code&gt;index&lt;/code&gt; template. Now,
under the hood Ember is still using a &lt;code&gt;App.IndexController&lt;/code&gt; controller
but it will define one on the fly. I will get into this in a future blog
post. When you call &lt;code&gt;reopen&lt;/code&gt; this is the Ember way to reopen and monkey
patch a class. As you can see the Ember Router syntax is similar to the
one in Rails. This is by design. We need the 2nd route there so our
&lt;code&gt;application.hbs&lt;/code&gt; template can compile as it is referencing the
&lt;code&gt;users.index&lt;/code&gt; route.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s write &lt;code&gt;app/assets/javascripts/templates/index.hbs&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;h1&amp;gt;Welcome!&amp;lt;/h1&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We need to do one last thing before we check out the homepage. By default, Rails includes a sample &lt;code&gt;index&lt;/code&gt; page in &lt;code&gt;public/index.html&lt;/code&gt;. If we were to go to the homepage now, we would see that.
But we want to see the index page we just made. To remove the Rails default page, simply run&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rm public/index.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;from the command line.&lt;/p&gt;

&lt;p&gt;That&amp;#39;s it. If you run your rails server and load the app you should see the following
&lt;img src=&quot;http://i.imgur.com/1j50C.png?1&quot; alt=&quot;Welcome&quot;&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You&amp;#39;ve built your first Ember app! Let&amp;#39;s make it do
something useful. We are going to add the &lt;code&gt;/users&lt;/code&gt; page, so edit
&lt;code&gt;app/assets/javascripts/templates/users.hbs&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Users&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;span3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;table&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;table table-striped&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;th&amp;gt;&lt;/span&gt;ID&lt;span class=&quot;tag&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Reload your app and you can click back and forth between &amp;#39;Users&amp;#39; and &amp;#39;Home&amp;#39;, thanks to the &lt;code&gt;linkTo&lt;/code&gt; actions we setup in &lt;code&gt;application.hbs&lt;/code&gt;. These actions map to controllers being automatically generated because we haven&amp;#39;t created them yet; those controllers automatically render the templates with the same naming convention. Does that sound familiar? That&amp;#39;s right, its our good friend &lt;a href=&quot;http://en.wikipedia.org/wiki/Convention_over_configuration&quot;&gt;Convention Over Configuration&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Now, when clicking between the two pages the nav is not properly updating the &lt;code&gt;active&lt;/code&gt; class on the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; tags. In Ember, you can &lt;a href=&quot;http://emberjs.com/guides/templates/binding-element-class-names&quot;&gt;bind element class names to actions&lt;/a&gt;. This will require a bit of code, but as we add more controllers I&amp;#39;ll show how we can easily reuse what we&amp;#39;re about to write. Let&amp;#39;s start by adding the bindings to &lt;code&gt;application.hbs&lt;/code&gt; Modify the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; tags in the nav menu to:&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isHome:active&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;Home&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;bindAttr&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;isUsers:active&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;users.index&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;Users&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This binding of &lt;code&gt;isHome:active&lt;/code&gt; tells Ember to make the class &lt;code&gt;active&lt;/code&gt; if the &lt;code&gt;isHome&lt;/code&gt; attribute on the controller is &lt;code&gt;true&lt;/code&gt;. If it is &lt;code&gt;false&lt;/code&gt; the value will be nothing. The same goes for &lt;code&gt;isUsers&lt;/code&gt;. Because this code lives in &lt;code&gt;application.hbs&lt;/code&gt; we need to add these attributes to &lt;code&gt;app/assets/javascripts/controllers/applicationController.coffee&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.ApplicationController = Ember.Controller.extend
  isHome: (-&amp;gt;
    @get(&#39;currentRoute&#39;) == &#39;home&#39;
  ).property(&#39;currentRoute&#39;)

  isUsers: (-&amp;gt;
    @get(&#39;currentRoute&#39;) == &#39;users&#39;
  ).property(&#39;currentRoute&#39;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://emberjs.com/guides/controllers&quot;&gt;Read more about Ember Controllers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each attribute is a function that will compare the &lt;code&gt;currentRoute&lt;/code&gt; attribute to a value and return that boolean result. We instruct the attribute to be a &lt;a href=&quot;http://emberjs.com/guides/object-model/computed-properties&quot;&gt;computed property&lt;/a&gt;. Computed properties are simple to understand: we tell Ember to automatically update the value of &amp;#39;isHome&amp;#39; when &lt;code&gt;currentRoute&lt;/code&gt; is &lt;code&gt;set&lt;/code&gt; to a different value. Ember will then instruct anything bound to that attribute to update as well.&lt;/p&gt;

&lt;p&gt;Finally, we&amp;#39;re going to update our routes to set &lt;code&gt;currentRoute&lt;/code&gt; depending upon the route. Let&amp;#39;s add two route classes to &lt;code&gt;app/assets/javascripts/routes.coffee&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.IndexRoute = Ember.Route.extend
  setupController: (controller, model) -&amp;gt;
    @controllerFor(&#39;application&#39;).set(&#39;currentRoute&#39;, &#39;home&#39;)

App.UsersRoute = Ember.Route.extend
  setupController: (controller, model) -&amp;gt;
    @controllerFor(&#39;application&#39;).set(&#39;currentRoute&#39;, &#39;users&#39;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Two new concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setupController&lt;/code&gt; is a function automatically called on each visit to the route. It will pass in an instance of the controller and a model if you supply one (we&amp;#39;ll see this in a bit)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;this.controllerFor&lt;/code&gt; When interacting with a specific controller you may want to modify a different controller. In this case the wrapping controller is &lt;code&gt;ApplicationController&lt;/code&gt; and we need to update the &lt;code&gt;currentRoute&lt;/code&gt; attribute. You &lt;em&gt;must&lt;/em&gt; use the &lt;code&gt;set&lt;/code&gt; function otherwise Ember won&amp;#39;t know to notify any &lt;a href=&quot;http://emberjs.com/guides/object-model/computed-properties/&quot;&gt;computed property observers&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now reload your app and click between the actions and you should see the active states properly set depending upon your route.&lt;/p&gt;

&lt;p&gt;Next, we&amp;#39;re going to start using real data. We&amp;#39;re going to fetch the collection of Users from the server and display them on the index page. Let&amp;#39;s start with telling Ember what our data store looks like in &lt;code&gt;app/assets/javascripts/store.coffee&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Store = DS.Store.extend()
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://emberjs.com/guides/models/the-rest-adapter&quot;&gt;Read more about Ember&amp;#39;s REST Adapter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The REST adapter allows us to pull from an API backend assuming certain conventions are followed in the URIs and JSON response. Thankfully we set this up properly in &lt;a href=&quot;http://reefpoints.dockyard.com/ember/2013/01/07/building-an-ember-app-with-rails-api-part-1.html&quot;&gt;Part 1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we&amp;#39;ll create a new model in &lt;code&gt;app/assets/javascripts/models/user.coffee&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.User = DS.Model.extend(
  firstName: DS.attr(&#39;string&#39;)
  lastName:  DS.attr(&#39;string&#39;)
  quote:     DS.attr(&#39;string&#39;)
  fullName: (-&amp;gt;
    &amp;quot;#{@get(&#39;firstName&#39;)} #{@get(&#39;lastName&#39;)}&amp;quot;
  ).property(&#39;firstName&#39;, &#39;lastName&#39;)
)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://emberjs.com/guides/models&quot;&gt;Read more about Ember models&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are defining each attribute that is coming over the wire, as well as a computed property that will combine &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;. If you&amp;#39;re wondering about that call to &lt;code&gt;property&lt;/code&gt;, you have to let Ember know when a method on an object is using a property computed from dependency properties on that object. Here &lt;code&gt;fullName&lt;/code&gt; depends on &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;. When we call &lt;code&gt;property&lt;/code&gt; and let Ember know which properties to observe, the &lt;code&gt;fullName&lt;/code&gt; property will update if either the &lt;code&gt;firstName&lt;/code&gt; or &lt;code&gt;lastName&lt;/code&gt; changes. If you like, you can &lt;a href=&quot;http://emberjs.com/guides/object-model/computed-properties/&quot;&gt;read more about computed properties&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we need to modify the &lt;code&gt;users&lt;/code&gt; route to fetch the data&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.UsersRoute = Ember.Route.extend
  model: -&amp;gt;
    App.User.find()
  setupController: (controller, model) -&amp;gt;
    @controllerFor(&#39;application&#39;).set(&#39;currentRoute&#39;, &#39;users&#39;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;App.User.find()&lt;/code&gt; makes a remote call, fetches the collection, and instantiates the models. This collection is then passed to &lt;code&gt;setupController&lt;/code&gt; through the &lt;code&gt;model&lt;/code&gt; attribute. We then assign this collection to the &lt;code&gt;users&lt;/code&gt; attribute on the controller. &lt;/p&gt;

&lt;p&gt;Now edit &lt;code&gt;app/assets/javascripts/templates/users.hbs&lt;/code&gt; to include a list of our users and an outlet through which we&amp;#39;ll render a users index page and our users show page.&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;span3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;table&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;table table-striped&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;th&amp;gt;&lt;/span&gt;ID&lt;span class=&quot;tag&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Name&lt;span class=&quot;tag&quot;&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;tag&quot;&gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;users.show&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;tag&quot;&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;span8&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;outlet&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We are linking to the &lt;code&gt;show&lt;/code&gt; named route and passing the instance of a &lt;code&gt;User&lt;/code&gt; (which is what &lt;code&gt;this&lt;/code&gt; refers to) as the paramater. Ember will pull out the id on the object and set that to the &lt;code&gt;:user_id&lt;/code&gt; segment on the path.&lt;/p&gt;

&lt;p&gt;We need to next update &amp;#39;App.Router&amp;#39; for the proper mapping&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.Router.map -&amp;gt;
  @resource &#39;users&#39;, -&amp;gt;
    @route &#39;show&#39;,
      path: &#39;/:user_id&#39;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note how we are matching against &lt;code&gt;:user_id&lt;/code&gt; and not &lt;code&gt;:id&lt;/code&gt; that Rails developers are used to.&lt;/p&gt;

&lt;p&gt;I must confess I don&amp;#39;t entirely understand why the &lt;code&gt;/&lt;/code&gt; map is necessary under &lt;code&gt;/users&lt;/code&gt;, I would have thought the top nesting could be used and it wouldn&amp;#39;t be necessary to redefine a root path. Please enlighten me in the comments! Ok, the router maps are updated. Let&amp;#39;s add the &lt;code&gt;show&lt;/code&gt; route.&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;App.UsersShowRoute = Ember.Route.extend
  model: (params) -&amp;gt;
    App.User.find(params.user_id)
  setupController: (controller, model) -&amp;gt;
    controller.set(&#39;content&#39;, model)
    @controllerFor(&#39;application&#39;).set(&#39;currentRoute&#39;, &#39;users&#39;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And we&amp;#39;ll add the &lt;code&gt;app/assets/javascripts/templates/users/show.hbs&lt;/code&gt; template&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;q&amp;gt;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/q&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;page-header&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{#&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt; &lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;error&quot;&gt;&#39;&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;btn&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;Back&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;{{/&lt;/span&gt;&lt;span class=&quot;attribute-name&quot;&gt;linkTo&lt;/span&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And finally, we&amp;#39;ll add the &amp;#39;app/assets/javascripts/users/index.hbs&amp;#39; template&lt;/p&gt;
&lt;div class=&quot;highlight handlebars &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;tag&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Please choose a user.&lt;span class=&quot;tag&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Reload your app and click through to the show page and you should see&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/jNKhnrJ.png&quot; alt=&quot;Show&quot;&gt;&lt;/p&gt;

&lt;p&gt;So we have only implemented the &amp;#39;Read&amp;#39; of &amp;#39;CRUD&amp;#39; in this part, but we have also introduced alot of new concepts. In &lt;a href=&quot;http://reefpoints.dockyard.com/ember/2013/01/10/building-an-ember-app-with-rails-api-part-3.html&quot;&gt;Part 3&lt;/a&gt; we will implement the &amp;#39;Create Update Destroy&amp;#39; actions.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Building an Ember app with RailsAPI - Part 1</title>
    <link rel="alternate" href="https://dockyard.com/blog/ember/2013/01/07/building-an-ember-app-with-rails-api-part-1" />
    <id>https://dockyard.com/blog/ember/2013/01/07/building-an-ember-app-with-rails-api-part-1</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ember" label="Ember.js"/><category term="javascript" label="JavaScript"/>
    <published>2013-01-07 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Setting up RailsAPI for writing an Ember App</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article was last updated on May 28, 2013 and reflects the state
 of Ember (1.0.0-rc4) and the latest build of Ember Data (0.13) as of
that date.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/bcardarella/ember-railsapi&quot;&gt;Fork the project on Github!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://ember-rails-api.herokuapp.com/&quot;&gt;Use the app live on Heroku&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lately I&amp;#39;ve been playing with &lt;a href=&quot;http://emberjs.com&quot;&gt;Ember.js&lt;/a&gt; and I have
really grown to love it. I get the same &amp;quot;AHA!&amp;quot; feeling I got building my
first &lt;a href=&quot;http://rubyonrails.org&quot;&gt;Rails&lt;/a&gt; app 7 years ago. Let&amp;#39;s see how to
build a simple
&lt;a href=&quot;http://en.wikipedia.org/wiki/Create,_read,_update_and_delete&quot;&gt;CRUD&lt;/a&gt; app
using the &lt;a href=&quot;https://github.com/rails-api/rails-api&quot;&gt;RailsAPI&lt;/a&gt; as the
backend. We&amp;#39;re going to build a new app and deploy to Heroku.&lt;/p&gt;

&lt;h2&gt;Part 1 - Getting Set Up&lt;/h2&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;gem install rails-api
rails-api new ember-app
cd ember-app
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Similar to the &lt;code&gt;rails&lt;/code&gt; command &lt;code&gt;RailsAPI&lt;/code&gt; comes with a &lt;code&gt;rails-api&lt;/code&gt;
command which under the hood is just using the normal &lt;code&gt;rails&lt;/code&gt; CLI code
but overriding some of the templates generated. Out of the box
&lt;code&gt;RailsAPI&lt;/code&gt; won&amp;#39;t generate the &lt;a href=&quot;http://guides.rubyonrails.org/asset_pipeline.html&quot;&gt;asset pipeline&lt;/a&gt; directories
as there is &lt;a href=&quot;https://github.com/rails-api/rails-api/issues/50&quot;&gt;still some
debate&lt;/a&gt; if it will use
&lt;a href=&quot;https://github.com/sstephenson/sprockets&quot;&gt;Sprockets&lt;/a&gt;,
&lt;a href=&quot;https://github.com/livingsocial/rake-pipeline&quot;&gt;Rake-Pipeline&lt;/a&gt; or some
other solution. In this example we&amp;#39;re going to use Sprockets as it will
save us a lot of time. &lt;code&gt;RailsAPI&lt;/code&gt; is bundled with
&lt;a href=&quot;https://github.com/rails/rails/blob/3-2-stable/actionpack/actionpack.gemspec&quot;&gt;ActionPack&lt;/a&gt;
which has &lt;code&gt;Sprockets&lt;/code&gt; as a dependency. All we need to do is add in the
directories&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;mkdir -p app/assets/{javascripts,stylesheets,images}
mkdir -p vendor/assets/{javascripts,stylesheets,images}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we need to copy in the vendored asset files. You can either build yourself our run the following to copy directly from my Github project&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;cd vendor/assets/javascripts
wget https://raw.github.com/bcardarella/ember-railsapi/master/vendor/assets/javascripts/ember-data.js
wget https://raw.github.com/bcardarella/ember-railsapi/master/vendor/assets/javascripts/ember.js
wget https://raw.github.com/bcardarella/ember-railsapi/master/vendor/assets/javascripts/jquery.js
wget https://raw.github.com/bcardarella/ember-railsapi/master/vendor/assets/javascripts/modernizr.js
cd ../../..
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note that if you&amp;#39;re a Mac user, just replace &lt;code&gt;wget&lt;/code&gt; (the Linux command) with &lt;code&gt;curl -O&lt;/code&gt; (the Unix command) on the above lines.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s setup the directory structure for our Ember app&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;mkdir -p app/assets/javascripts/{controllers,models,views,templates}
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And now we&amp;#39;ll setup the load order in our &lt;code&gt;app/assets/javascripts/application.coffee&lt;/code&gt; file&lt;/p&gt;
&lt;div class=&quot;highlight coffeescript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;#= require modernizr
#= require jquery
#= require handlebars
#= require ember
#= require ember-data
#= require bootstrap
#= require_self
#= require store
#= require routes
#= require_tree ./controllers
#= require_tree ./models
#= require_tree ./templates
#= require_tree ./views

window.App = Ember.Application.create()
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Add the &lt;code&gt;routes.coffee&lt;/code&gt; and &lt;code&gt;store.coffee&lt;/code&gt; files:&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;touch app/assets/javascripts/routes.coffee
touch app/assets/javascripts/store.coffee
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And the &lt;code&gt;app/assets/stylesheets/application.sass&lt;/code&gt; file&lt;/p&gt;
&lt;div class=&quot;highlight sass &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;directive&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bootstrap&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;tag&quot;&gt;body&lt;/span&gt;
  &lt;span class=&quot;key&quot;&gt;padding-top&lt;/span&gt;: &lt;span class=&quot;float&quot;&gt;60px&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That was a good amount of setup. Now we have the application structure for an Ember app in our asset pipeline. This will make things cleaner once we start coding.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s setup the necessary gem dependencies in our &lt;code&gt;Gemfile&lt;/code&gt;. Just replace the entire contents with the following:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;source &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;https://rubygems.org&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

ruby &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;2.0.0&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;rails&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;3.2.13&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;rails-api&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;thin&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;active_model_serializers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:github&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;rails-api/active_model_serializers&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

group &lt;span class=&quot;symbol&quot;&gt;:development&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;debugger&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;sqlite3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

group &lt;span class=&quot;symbol&quot;&gt;:production&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;pg&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

group &lt;span class=&quot;symbol&quot;&gt;:assets&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;sass-rails&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;~&amp;gt; 3.2&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;coffee-rails&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;~&amp;gt; 3.2&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;compass-rails&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;uglifier&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;bootstrap-sass&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;~&amp;gt; 2.0.3.0&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;handlebars_assets&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;0.12.3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

group &lt;span class=&quot;symbol&quot;&gt;:development&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  gem &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;quiet_assets&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There are two gems to take note of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rails-api/active_model_serializers&quot;&gt;ActiveModelSerializers&lt;/a&gt; is a project that is written by the &lt;code&gt;Ember&lt;/code&gt; core team which will normalize the &lt;a href=&quot;http://en.wikipedia.org/wiki/JSON&quot;&gt;JSON&lt;/a&gt; output for models in a &lt;code&gt;Rails&lt;/code&gt; app.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/leshill/handlebars_assets&quot;&gt;HandlebarsAssets&lt;/a&gt; will allow the &lt;code&gt;AssetPipeline&lt;/code&gt; to compile &lt;a href=&quot;http://handlebarsjs.com/&quot;&gt;Handlebars&lt;/a&gt; templates which is required for Ember. There is the &lt;a href=&quot;https://github.com/emberjs/ember-rails&quot;&gt;Ember-Rails&lt;/a&gt; gem which will also do this but I have found &lt;code&gt;HandlebarsAssets&lt;/code&gt; to be a leaner solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After this, don&amp;#39;t forget to run &lt;code&gt;bundle install&lt;/code&gt; from the command line to pick up the gems we just added.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s create a simple model and the serializer&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;rails-api g model User first_name:string last_name:string quote:text
rails-api g serializer User
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Run &amp;#39;rake db:migrate&amp;#39; to run the migration for our User model. Now open up &lt;code&gt;app/serializers/user_serializer.rb&lt;/code&gt; and add the fields that require serialization&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;UserSerializer&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveModel&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Serializer&lt;/span&gt;
  attributes &lt;span class=&quot;symbol&quot;&gt;:id&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:first_name&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:last_name&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:quote&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Again, this will instruct &lt;code&gt;Rails&lt;/code&gt; to turn our &lt;code&gt;ActiveRecord&lt;/code&gt; object into a &lt;code&gt;JSON&lt;/code&gt; object properly normalized for &lt;code&gt;Ember&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Let&amp;#39;s write the Controller. Create and edit &lt;code&gt;app/controllers/users_controller.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;UsersController&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;index&lt;/span&gt;
    render &lt;span class=&quot;key&quot;&gt;json&lt;/span&gt;: &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.all
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Take note that we are inheriting &lt;code&gt;ApplicationController&lt;/code&gt; but in a &lt;code&gt;RailsAPI&lt;/code&gt; app &lt;code&gt;ApplicationController&lt;/code&gt; itself inherits from &lt;code&gt;ActionController::API&lt;/code&gt; instead of &lt;code&gt;ActionController::Base&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This basic controller will serve up all of our users to our Ember app. We&amp;#39;ll add more later.&lt;/p&gt;

&lt;p&gt;Now let&amp;#39;s add some routes to &lt;code&gt;config/routes.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;EmberApp&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Application&lt;/span&gt;.routes.draw &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;FormatTest&lt;/span&gt;
    attr_accessor &lt;span class=&quot;symbol&quot;&gt;:mime_type&lt;/span&gt;

    &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;(format)
      &lt;span class=&quot;instance-variable&quot;&gt;@mime_type&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;Mime&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Type&lt;/span&gt;.lookup_by_extension(format)
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;matches?&lt;/span&gt;(request)
      request.format == mime_type
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  resources &lt;span class=&quot;symbol&quot;&gt;:users&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:except&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:edit&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:constraints&lt;/span&gt; =&amp;gt; &lt;span class=&quot;constant&quot;&gt;FormatTest&lt;/span&gt;.new(&lt;span class=&quot;symbol&quot;&gt;:json&lt;/span&gt;)
  get &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;*foo&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:to&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember#index&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:constraints&lt;/span&gt; =&amp;gt; &lt;span class=&quot;constant&quot;&gt;FormatTest&lt;/span&gt;.new(&lt;span class=&quot;symbol&quot;&gt;:html&lt;/span&gt;)
  get &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:to&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ember#index&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:constraints&lt;/span&gt; =&amp;gt; &lt;span class=&quot;constant&quot;&gt;FormatTest&lt;/span&gt;.new(&lt;span class=&quot;symbol&quot;&gt;:html&lt;/span&gt;)
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A few things are happening here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are constraining against the format with a custom &lt;code&gt;FormatTest&lt;/code&gt; class. We only want to map certain routes to &lt;code&gt;JSON&lt;/code&gt; requests and certain routes to &lt;code&gt;HTML&lt;/code&gt; requesets.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;get &amp;#39;*foo&amp;#39;...&lt;/code&gt; will greedily match all routes except &lt;code&gt;/&lt;/code&gt; so we have the following line. We want to direct all &lt;code&gt;HTML&lt;/code&gt; requests to a single &lt;code&gt;controller#action&lt;/code&gt;. I will go into the reason why in a bit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let&amp;#39;s create that &lt;code&gt;Ember&lt;/code&gt; controller. This will act as the primary application serving controller that is hit when people visit the app. Create and edit &lt;code&gt;app/controllers/ember_controller.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;EmberController&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActionController&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;; &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note that we are inheriting from &lt;code&gt;ActionController::Base&lt;/code&gt; this time and not &lt;code&gt;ApplicationController&lt;/code&gt;. This is so that the controller actions can respond to non &lt;code&gt;JSON&lt;/code&gt; requests.&lt;/p&gt;

&lt;p&gt;Now we will add the view in &lt;code&gt;app/views/ember/index.html.erb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight erb &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;doctype&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;attribute-name&quot;&gt;lang&lt;/span&gt;=&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;en&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;tag&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; stylesheet_link_tag &lt;span class=&quot;symbol&quot;&gt;:application&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:media&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:all&lt;/span&gt; &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; javascript_include_tag &lt;span class=&quot;symbol&quot;&gt;:application&lt;/span&gt; &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;tag&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Title&lt;span class=&quot;tag&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;tag&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;tag&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That is all the view that your Ember app will need. Ember will automatically attach its own default template to the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s add some data to &lt;code&gt;db/seeds.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.create(&lt;span class=&quot;symbol&quot;&gt;:first_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;William&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:last_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Harrison&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:quote&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I&#39;m just singin&#39; in the rain!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.create(&lt;span class=&quot;symbol&quot;&gt;:first_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Abraham&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:last_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Lincoln&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:quote&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I&#39;d like to see a show tonight.&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now run your migrations and seed&lt;/p&gt;
&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;rake db:migrate db:seed
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Ok, now our app is in a good spot to start developing an Ember app with. Let&amp;#39;s review what we did&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generated a new app using &lt;code&gt;rails-api&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set up the javascript and stylesheet assets&lt;/li&gt;
&lt;li&gt;Wrote a very simple JSON API for returning all users&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In &lt;a href=&quot;http://reefpoints.dockyard.com/ember/2013/01/09/building-an-ember-app-with-rails-api-part-2.html&quot;&gt;Part 2&lt;/a&gt; we&amp;#39;ll build the Ember app itself.&lt;/p&gt;
</content>
  </entry><entry>
    <title>DismissibleHelpers released</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2013/01/04/dismissible_helpers-released" />
    <id>https://dockyard.com/blog/ruby/2013/01/04/dismissible_helpers-released</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="gems" label="Gems"/>
    <published>2013-01-04 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Add simple to implement help text that users can dismiss</summary>
    <content type="html">&lt;p&gt;Have an application where you want to add some help text for the user,
but they really only need to see it once? With the
&lt;a href=&quot;https://github.com/dockyard/dismissible_helpers&quot;&gt;&lt;code&gt;dismissible_helpers&lt;/code&gt;&lt;/a&gt;
gem, you can quickly add dismissible help text to your application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/dismissible_helpers&quot;&gt;View the project on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://dismissible-helpers-example.herokuapp.com/&quot;&gt;View the demo here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/dismissible_helpers_example&quot;&gt;View the demo source code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;What you get&lt;/h2&gt;

&lt;p&gt;DismissibleHelpers includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DismissibleHelpers View Helper - Renders the help text only if the visitor
has not dismissed it&lt;/li&gt;
&lt;li&gt;DismissedHelpers Routes and controller - Handles the JavaScript requests
to store the dismissal state&lt;/li&gt;
&lt;li&gt;DismissedHelpers Javascript - Handles the front end interactions with
the help text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, &lt;code&gt;dismissible_helpers&lt;/code&gt; will use a cookie to store the
dismissal status of the help text.&lt;/p&gt;

&lt;h2&gt;Three minute setup&lt;/h2&gt;

&lt;p&gt;To start using &lt;code&gt;dismissible_helpers&lt;/code&gt; without any customization, you only
three steps away.&lt;/p&gt;

&lt;ol&gt;

  &lt;li&gt;&lt;p&gt; Add &lt;code&gt;dismissible_helpers_routes&lt;/code&gt; to your &lt;code&gt;config/routes.rb&lt;/code&gt;

```ruby
YourApplication::Application.routes.draw do
  dismissible_helpers_routes

  # Your other routes
end```
  &lt;/p&gt;&lt;/li&gt;

  &lt;li&gt;&lt;p&gt; Add the Javascript: Add the following to your &lt;code&gt;app/assets/javascripts/application.js&lt;/code&gt;.

```javascript
// Your other require statments
//=require dismissible_helpers
//=require_self

$(function(){
  $(&#39;.dismissible&#39;).dismissible()
})```
  &lt;/p&gt;&lt;/li&gt;

  &lt;li&gt;&lt;p&gt; Call the &lt;code&gt;render_dismissible_helper&lt;/code&gt; method with the string you want to
       render. The string passed to the method will be processed by the I18n method
       &lt;code&gt;t&lt;/code&gt;, so the content of the help message should be stored in your localization
       file.

```erb
&lt;%= render_dismissible_helper &#39;help.some_help_message&#39; %&gt;
```
  &lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;Advanced setup&lt;/h2&gt;

&lt;h3&gt;Changing the way the help text is removed&lt;/h3&gt;

&lt;p&gt;By default, the dismissed helper is removed from the page via
&lt;code&gt;$(helper).remove()&lt;/code&gt;. This can be customized by passing a callback to the
&lt;code&gt;.dismissible()&lt;/code&gt; call. To use jQuery&amp;#39;s &lt;code&gt;.slideUp()&lt;/code&gt; you would use the
following call:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(){
  &lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.dismissible&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).dismissible({
    &lt;span class=&quot;function&quot;&gt;success&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(helper){
      helper.slideUp(); &lt;span class=&quot;comment&quot;&gt;//&#39;helper&#39; is the jQuery-wrapped element&lt;/span&gt;
    }
  });
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Storing dismissed helpers for authenticated users&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;dismissible_helpers&lt;/code&gt; can store the help text dismissal state on a
user/account. That way, when a user dismisses some help text, it follows
them across browsers.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dismissible_helpers&lt;/code&gt; will attempt to retrieve the authenticated user by
checking for a &lt;code&gt;current_user&lt;/code&gt; helper method. If the
ApplicationController responds to &lt;code&gt;current_user&lt;/code&gt;, &lt;code&gt;dismissible_helpers&lt;/code&gt;
will check to see if the returned object has a &lt;code&gt;dismissed_helpers&lt;/code&gt;
attribute. It will then add the dismissed help text to that model.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dismissible_helpers&lt;/code&gt; expects that the &lt;code&gt;dismissed_helpers&lt;/code&gt; attribute is
an array. With vanilla ActiveRecord, you can achieve this with attribute
serialization:&lt;/p&gt;

&lt;p&gt;First, add the column to your model (we&amp;#39;ll assume it&amp;#39;s an Account class
in this example)&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;AddDismissedHelpersToAccounts&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Migration&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;up&lt;/span&gt;
    add_column &lt;span class=&quot;symbol&quot;&gt;:accounts&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:dismissed_helpers&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:text&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;down&lt;/span&gt;
    remove_column &lt;span class=&quot;symbol&quot;&gt;:accounts&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:dismissed_helpers&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then add the &lt;code&gt;serialize&lt;/code&gt; call to your model&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Account&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  serialize &lt;span class=&quot;symbol&quot;&gt;:dismissed_helpers&lt;/span&gt;, &lt;span class=&quot;constant&quot;&gt;Array&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you are using PostgreSQL as your database, you could use
&lt;a href=&quot;https://github.com/dockyard/postgres_ext&quot;&gt;postgres_ext&lt;/a&gt; to
add native array support to your models. You would just need the
following migration to add the dismissed_helpers attribute
to your model:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;AddDismissedHelpersToAccounts&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Migration&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;up&lt;/span&gt;
    add_column &lt;span class=&quot;symbol&quot;&gt;:accounts&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:dismissed_helpers&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:string&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;down&lt;/span&gt;
    remove_column &lt;span class=&quot;symbol&quot;&gt;:accounts&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:dismissed_helpers&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;Hopefully you find the gem useful. If you find any issues with it, 
&lt;a href=&quot;https://github.com/dockyard/dismissible_helpers/issues&quot;&gt;let us know&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Integration is Hard</title>
    <link rel="alternate" href="https://dockyard.com/blog/politics/2013/01/03/integration-is-hard" />
    <id>https://dockyard.com/blog/politics/2013/01/03/integration-is-hard</id>
    <category term="postgresql" label="PostgreSQL"/><category term="politics" label="Politics"/>
    <published>2013-01-03 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Chris Gill</name></author>
    <summary>A description of techniques used to integrate with various vendors on a recent DockYard project for the AFL-CIO&#39;s Super PAC Worker&#39;s Voice.</summary>
    <content type="html">&lt;p&gt;There&amp;#39;s no one-size-fits-all approach to integrating with external
systems because each system comes with its own unique requirements and
constraints.  This article aims to describe some of the varying
approaches we used to integrate with external systems in a recent
project we built for the &lt;a href=&quot;http://www.aflcio.org&quot;&gt;AFL-CIO&lt;/a&gt;&amp;#39;s Super PAC
&lt;a href=&quot;http://www.workersvoice.org&quot;&gt;Worker&amp;#39;s Voice&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this project, integration with external vendors was the biggest technical hurdle to clear in order to ensure a successful launch.  The project, called &lt;a href=&quot;http://repurpose.workersvoice.org/&quot;&gt;RePurpose&lt;/a&gt;, gives volunteers and activists a way to choose how the movement&amp;#39;s resources get deployed.  The more volunteering and activism a person does, the more RePurpose points they earn, which they can then use to direct the funding of things like more canvassers, direct mail pieces or online ads.  &lt;/p&gt;

&lt;p&gt;It&amp;#39;s a way to give the people on the ground a say in how the money gets spent.&lt;/p&gt;

&lt;p&gt;The volunteering and activism data for which RePurpose points get awarded exists in several separate systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://www.ngpvan.com&quot;&gt;VAN&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VAN is the de facto standard tool used everywhere in progressive politics - from small local races all the way up to the Obama campaign.  It&amp;#39;s an organizing tool that stores volunteer records, canvass records (door knocks and phone calls), activist codes, and other organizing data used by progressive campaigns and organizations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://www.salsalabs.com&quot;&gt;Salsa Labs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Salsa has a platform with a rich API and tools to create fundraising and advocacy campaigns and manage organizer data.  It stores supporter records, online donation records, and pledges to take action - among other things.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;http://amicushq.com/&quot;&gt;Amicus&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amicus is a new online tool that leverages Facebook connections of volunteers to enhance fundraising and advocacy campaigns.  It stores a set of volunteer records, friend invite records, and social calling records.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was straightforward - RePurpose needed to know when a volunteer
was performing tasks in external systems, so that the user could receive
points in RePurpose for those tasks.  RePurpose itself has a Task model
that supports multiple kinds of tasks in the various external systems -
survey tasks, activist code tasks, and
&lt;a href=&quot;http://en.wikipedia.org/wiki/Canvassing&quot;&gt;canvass&lt;/a&gt; tasks in VAN, donation tasks and action tasks in Salsa, and friend invite tasks and call tasks in Amicus.  So a RePurpose administrator could set up a task that would award 10 RePurpose points each time a volunteer knocked on a door, made a phone call, or made a donation.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s how we did it in each system:&lt;/p&gt;

&lt;h2&gt;VAN Sync&lt;/h2&gt;

&lt;p&gt;VAN, which was recently voted &lt;a href=&quot;http://rootscamp.neworganizing.com/awards/2012/&quot;&gt;Most Valuable
Tech&lt;/a&gt; at &lt;a href=&quot;http://rootscamp.neworganizing.com/&quot;&gt;RootsCamp
2012&lt;/a&gt;, has a
&lt;a href=&quot;http://en.wikipedia.org/wiki/SOAP&quot;&gt;SOAP&lt;/a&gt;-based API that allows us to list survey questions, list activist codes, and create and list volunteers (among other things) - all of which we use to get that data into RePurpose, but the API doesn&amp;#39;t support retrieving the raw canvasser data - which is the piece we really need to award credit.  To get this data the two options were a nightly sync of flat files, or getting direct access to a replicated database.  We opted for the flat file sync as we knew it had worked for other organizations (among them the Democratic National Committee) and the replicated database approach would have incurred extra time, expense, and risk.&lt;/p&gt;

&lt;p&gt;We worked with the great folks at VAN to get a nightly data sync into
place.  Each night around 3am, VAN uploads a zipped TSV (tab-separated
values) export of the relevant data from all the relevant tables in the
AFL-CIO&amp;#39;s VAN database.  This is not a delta - because the data size is
relatively low (&amp;lt; 1 GB), we receive the full data dump each night.  We
then unzip, verify that all the files we expect are present, convert
character encodings from
&lt;a href=&quot;http://en.wikipedia.org/wiki/Windows-1252&quot;&gt;CP1252&lt;/a&gt; to
&lt;a href=&quot;http://en.wikipedia.org/wiki/UTF-8&quot;&gt;UTF8&lt;/a&gt; (VAN uses &lt;a href=&quot;http://en.wikipedia.org/wiki/Microsoft_SQL_Server&quot;&gt;MSSQL
Server&lt;/a&gt;), and load
this data into auxiliary tables in the RePurpose database using
&lt;a href=&quot;http://www.postgresql.org&quot;&gt;PostgreSQL&lt;/a&gt;&amp;#39;s
&amp;quot;&lt;a href=&quot;http://www.postgresql.org/docs/9.2/static/sql-copy.html&quot;&gt;COPY&lt;/a&gt;&amp;quot; command.  All told it takes about 5 minutes each night to process, load, and index around 700MB of data from flat files to get it into PostgreSQL and ready to be used.  Then based on the new data we award credit to volunteers for completing tasks.  This approach handles the most data of any of the external integrations and does so reliably.  It has one drawback which is that the data can be at most 24 hours stale by the time we receive it, which is not ideal but is certainly workable.  In practice this has not been a problem for us.&lt;/p&gt;

&lt;h2&gt;Salsa API&lt;/h2&gt;

&lt;p&gt;Salsa has a
&lt;a href=&quot;http://en.wikipedia.org/wiki/Representational_state_transfer&quot;&gt;REST&lt;/a&gt;-based
&lt;a href=&quot;http://en.wikipedia.org/wiki/Application_programming_interface&quot;&gt;API&lt;/a&gt; for authenticating and for creating and retrieving objects in the Salsa system.  For RePurpose, that meant creating and listing supporters (Salsa&amp;#39;s name for a volunteer record), listing donation pages, listing donations, and listing completed actions like making a pledge or writing a letter to an editor.  In the context of RePurpose we were most interested in listing completed donations and completed actions so we could award the person who completed the task with their RePurpose points.  Since we could get all this information via the API, and since the API can list objects created since a certain timestamp, we set up a scheduled job to poll the API and ask for anything new that has come in since the last record we retrieved.  This job runs every 10 minutes and gets us pretty close to realtime - if you make a donation through one of the Salsa donation pages that&amp;#39;s connected to a RePurpose task, your points will be credited to you within 5 minutes on average.&lt;/p&gt;

&lt;h2&gt;Amicus Exports&lt;/h2&gt;

&lt;p&gt;The Amicus API was still a work in progress during the RePurpose project, so we could not use it - but they did have an on-demand user export that could be programmatically triggered.  Since the user export contained all the information we needed about how many calls a user had attempted and how many friends they had invited on Facebook, this would get us where we needed to be.  We would import the Amicus users nightly on a schedule and load them into auxiliary tables in the RePurpose database, which were then used to award credit to the folks making calls and inviting friends.  Since we could trigger the export on demand, we also added a button to the RePurpose admin area to allow administrators to reload the Amicus data on demand and credit any new arrivals.&lt;/p&gt;

&lt;h2&gt;Matching&lt;/h2&gt;

&lt;p&gt;You&amp;#39;ve heard how we get the data into the RePurpose system, but how do we match the volunteers from the various external systems up with the users in RePurpose?  &lt;/p&gt;

&lt;p&gt;There are all kinds of pitfalls in implementing person matching, like trying to match up on variations of a first name, or variations of a street address, or keeping track of previous known-good addresses.  Complexity can quickly spiral out of control for marginal benefit.  For this project we went with a simple assumption - all matching would occur via email address.  So if a user was doing things in the field, which gets recorded into VAN - they should use the same email address that they would use to create their RePurpose account.  Likewise for Salsa and Amicus.  Since each of these external systems stores an email address for the volunteer, with this simple assumption, the matching logic becomes simple - comparing lowercase versions of email addresses.&lt;/p&gt;

&lt;h2&gt;Awarding Credit&lt;/h2&gt;

&lt;p&gt;There were some wrinkles with awarding credit for tasks performed in external systems.  Since each task hinged on an external datapoint, it was critical to uniquely identify these datapoints.  For most tasks, the granularity of data allowed us to use the primary key of the foreign data source as the unique identifier.  In some cases the data would just be an aggregate count, like &amp;quot;15 calls made&amp;quot; - in which case we would generate our own idempotent IDs for those calls so as to award credit once and have a way to prevent awarding credit for the same call a second time.  In addition to keeping things crediting properly, this had the added benefit of allowing any RePurpose points in the system can be traced back to the explicit data point in the external system that was responsible for creating them.&lt;/p&gt;

&lt;h2&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;Now that you&amp;#39;ve seen how we took three different approaches to integrate
with three different systems, you&amp;#39;re probably thinking that integration
can be tricky.  But if you&amp;#39;re in a progressive organization that uses
VAN, Salsa, or Amicus - remember that &lt;a href=&quot;https://dockyard.com/contact&quot;&gt;here at DockYard we have the
expertise and experience to make it look
easy&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry><entry>
    <title>OpenHack Boston 1.0</title>
    <link rel="alternate" href="https://dockyard.com/blog/community/2012/10/26/openhack-boston" />
    <id>https://dockyard.com/blog/community/2012/10/26/openhack-boston</id>
    <category term="community" label="Community"/>
    <published>2012-10-26 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Come one, come all!</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/a3LfvgG.png&quot; alt=&quot;OpenHack&quot;&gt;
Last night we hosted Boston&amp;#39;s first
&lt;a href=&quot;http://openhack.github.com/&quot;&gt;OpenHack&lt;/a&gt;
event.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/qrush&quot;&gt;Nick Quaranto&lt;/a&gt; started OpenHack at his &lt;a href=&quot;http://coworkbuffalo.com/&quot;&gt;CoWorkBuffalo&lt;/a&gt; office space,
based upon &lt;a href=&quot;http://bostonrb.org&quot;&gt;BostonRB&lt;/a&gt;&amp;#39;s former (don&amp;#39;t get me
started) Hackfests. The idea is pretty simple: a quiet space with food,
drinks, and wifi is provided. Developers show up and hack on some
software for a few hours.&lt;/p&gt;

&lt;p&gt;On 2-day notice we had 11 in attendance and all around everyone had a
very productive night. Currently our office maxes out at 20 chairs so until we buy more
we cannot accept over 20, but next month we will open the
event to a wider audience. We want to welcome more than just Ruby devs
(with the exception of 2 all were Ruby devs) to the event.&lt;/p&gt;

&lt;p&gt;Follow &lt;a href=&quot;http://twitter.com/dockyard&quot;&gt;@DockYard&lt;/a&gt; for all Boston OpenHack
announcements.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Expanding the Yard</title>
    <link rel="alternate" href="https://dockyard.com/blog/design/2012/10/11/expanding-the-yard" />
    <id>https://dockyard.com/blog/design/2012/10/11/expanding-the-yard</id>
    <category term="design" label="Design"/>
    <published>2012-10-11 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Angelo Simeoni</name></author>
    <summary>The story of how we reimagined our site.</summary>
    <content type="html">&lt;div class=&quot;one&quot;&gt;
  &lt;div class=&quot;content&quot;&gt;
    &lt;h2&gt;Outgrowing simplicity&lt;/h2&gt;
    &lt;p&gt;The first version of our site was contained within a single page. At the time, it served its purpose well. As we added more, it began to feel like it trying to do too much. Upon recognizing this, we began reimagining our site.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;two&quot;&gt;
  &lt;div class=&quot;content&quot;&gt;
    &lt;h2&gt;Structural changes&lt;/h2&gt;
    &lt;p&gt;The very first step we took was to establish a reasonable structure of our new site. This helped to inform the site content, and much of the new site design.&lt;/p&gt;
    &lt;p&gt;We decided to make the landing page an overview of DockYard. Our work deserved its own place to be shown. We have added people to our team, and we wanted a page dedicated to community &amp; open source projects. We have this blog thing, and we also wanted a dedicated contact page.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;three&quot;&gt;
  &lt;div class=&quot;content&quot;&gt;
    &lt;h2&gt;Design &amp; code&lt;/h2&gt;
    &lt;p&gt;After the structural decisions had been made, it was time to put down some design. This was done primarily in the browser using actual code. This allowed rapid iteration over page layout, content tweaks, and especially mobile design. Being able to try things almost right away in browser informed many design decisions.&lt;/p&gt;
    &lt;p&gt;With the new design, the Narwin (half narwhal, half penguin) was introduced as our mascot and overseer of all things nautical. We have high confidence that he will serve us loyally now and in the future.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;four&quot;&gt;
  &lt;div class=&quot;content&quot;&gt;
    &lt;h2&gt;Well done&lt;/h2&gt;
    &lt;p&gt;It was a lot of fun to reimagine our site and we are all proud of the result. It is designed to grow and evolve along with us.&lt;/p&gt;
    &lt;p&gt;There are plenty of hidden surprises in the new site. See if you can find an easter egg or two.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content>
  </entry><entry>
    <title>ClientSideValidations 3.2 Released!</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/10/09/client-side-validations-3-2-released" />
    <id>https://dockyard.com/blog/ruby/2012/10/09/client-side-validations-3-2-released</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="gems" label="Gems"/>
    <published>2012-10-09 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Better late than never</summary>
    <content type="html">&lt;p&gt;I just released &lt;a href=&quot;https://github.com/bcardarella/client_side_validations&quot;&gt;ClientSideValidations 3.2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a very big release for the gem, one that took &lt;em&gt;way&lt;/em&gt; too much
time to get done. I want to start by re-introducing people to the gem,
what the value is, and what the changes for 3.2 are.&lt;/p&gt;

&lt;p&gt;ClientSideValidations is just that, it will extract the validations from
your model and apply them to your forms on the client. The
&lt;a href=&quot;https://github.com/bcardarella/client_side_validations/blob/master/README.md&quot;&gt;README&lt;/a&gt;
has more comprehensive instructions. But here is the quick guide:&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;rails.validation.js&lt;/code&gt; to your asset pipeline, then add &lt;code&gt;:validate =&amp;gt;
true&lt;/code&gt; to your form like so:&lt;/p&gt;
&lt;div class=&quot;highlight erb &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; form_for &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:validate&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |f| &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And that is it. If you have more &lt;a href=&quot;https://github.com/bcardarella/client_side_validations/blob/master/README.md#conditional-validators&quot;&gt;complex validators&lt;/a&gt; or 
&lt;a href=&quot;https://github.com/bcardarella/client_side_validations/blob/master/README.md#custom-validators&quot;&gt;custom validators&lt;/a&gt;
on your models then you can quickly support these as well.&lt;/p&gt;

&lt;h2&gt;Changes&lt;/h2&gt;

&lt;p&gt;Version 3.2 brings many changes to the gem. The first of which is that
from this version on we will be following &lt;a href=&quot;http://semver.org&quot;&gt;Semantic Versioning&lt;/a&gt; or trying our best to do so.&lt;/p&gt;

&lt;p&gt;The next change, and the biggest backward-incompatible change, is that
the support for &lt;code&gt;SimpleForm&lt;/code&gt;, &lt;code&gt;Formtastic&lt;/code&gt;, &lt;code&gt;Mongoid&lt;/code&gt;, and &lt;code&gt;MongoMapper&lt;/code&gt;
have been removed. These have been put into their own
&lt;a href=&quot;https://github.com/bcardarella/client_side_validations/wiki/Plugins&quot;&gt;plugins&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/client_side_validations-simple_form&quot;&gt;SimpleForm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/client_side_validations-formtastic&quot;&gt;Formtastic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/client_side_validations-mongoid&quot;&gt;Mongoid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/client_side_validations-mongo_mapper&quot;&gt;MongoMapper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will be the convetion from now on. The &lt;code&gt;ClientSideValidations&lt;/code&gt; gem
itself will only support &lt;code&gt;Rails&lt;/code&gt; out of the box. If there are additional
FormBuilders or ORMs that people need support for these will be done so
via the plugins. This will allow for quicker bug fixes and less
complexity in the core gem.&lt;/p&gt;

&lt;p&gt;I have also released a gem for &lt;a href=&quot;https://github.com/dockyard/client_side_validations-turbolinks&quot;&gt;Turbolinks support&lt;/a&gt;.
Turbolinks support will be part of the core gem for the next release
(4.0).&lt;/p&gt;

&lt;p&gt;There have been a significant number of bug fixes for this release. If
you ran into a bug before odds are it is now resolved.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Proc&lt;/code&gt;s are now fullow supported in &lt;code&gt;ActiveModel&lt;/code&gt; validators, you just
have to force the validation to evaluate:&lt;/p&gt;
&lt;div class=&quot;highlight erb &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; f.text_field, &lt;span class=&quot;symbol&quot;&gt;:validate&lt;/span&gt; =&amp;gt; { &lt;span class=&quot;symbol&quot;&gt;:length&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt; } &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I have also added a FormBuilder method for adding validations for
attributes that are not being written to the form but may be added
dynamically later:&lt;/p&gt;
&lt;div class=&quot;highlight erb &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;&amp;lt;%=&lt;/span&gt; f.validate &lt;span class=&quot;symbol&quot;&gt;:age&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:weight&lt;/span&gt; &lt;span class=&quot;inline-delimiter&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This method can also take validator specific options.&lt;/p&gt;

&lt;h2&gt;JavaScript API Additions and Changes&lt;/h2&gt;

&lt;p&gt;The first major change is that &lt;code&gt;data-validate=&amp;quot;true&amp;quot;&lt;/code&gt; is no longer
rendered on the inputs server-side. It is added to the input at
run-time.&lt;/p&gt;

&lt;p&gt;The second is the addition of some &lt;a href=&quot;https://github.com/bcardarella/client_side_validations/blob/master/README.md#enabling-disabling-and-resetting-on-the-client&quot;&gt;jQuery functions&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(form or input).enableClientSideValidations();
&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(form or input).disableClientSideValidations();
&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(form).resetClientSideValidations();
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$.fn.enableClientSideValidations()&lt;/code&gt; acts upon either a form or input
and will enable them for ClientSideValidations. If you are adding
forms or inputs dynamically to the DOM via AJAX or some other means you
&lt;em&gt;need&lt;/em&gt; to call this function on them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$.fn.disableClientSideValidations()&lt;/code&gt; acts upon either a form or an
input and will disable them for ClientSideValidations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$.fn.resetClientSideValidations()&lt;/code&gt; will reset the validations. This
means disabling, removing all error messages, and enabling
validaitons.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Security&lt;/h2&gt;

&lt;p&gt;There have been some security fixes. Mostly around the &lt;code&gt;Uniqueness&lt;/code&gt;
middleware.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Calls to the uniqueness middleware only act upon models and
attributes that have a uniqueness validator defined in the model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href=&quot;https://github.com/bcardarella/client_side_validations/blob/master/README.md#security&quot;&gt;API for turning off uniqueness app-wide has been changed&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Backwards incompatiable changes&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you were relying upon &lt;code&gt;data-validate=&amp;quot;true&amp;quot;&lt;/code&gt; being rendered on the
inputs from the server your code will break.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ClientSideValidations::Config.uniqueness_validator_disabled&lt;/code&gt; has been
removed. Please add &lt;code&gt;ClientSideValidations::Config.disabled_validators
= [:uniqueness]&lt;/code&gt; to your initializer if you require this functionality.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please give the gem a try and &lt;a href=&quot;http://twitter.com/bcardarella&quot;&gt;let me know&lt;/a&gt; what you think!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Querying PostgreSQL datatypes in ActiveRecord with postgres_ext</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/09/21/querying-postgresql-datatypes-in-active-record-with-postgres_ext" />
    <id>https://dockyard.com/blog/ruby/2012/09/21/querying-postgresql-datatypes-in-active-record-with-postgres_ext</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="postgresql" label="PostgreSQL"/><category term="gems" label="Gems"/>
    <published>2012-09-21 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Returning records based on array elements and network subnets</summary>
    <content type="html">&lt;p&gt;I created the &lt;a href=&quot;https://github.com/dockyard/postgres_ext&quot;&gt;postgres_ext&lt;/a&gt; gem to add ActiveRecord support for 
PostgreSQL datatypes in Rails 3.2+. So far, I have added support for
the CIDR, INET, MACADDR, UUID, and array datatypes. &lt;a href=&quot;https://github.com/dockyard/postgres_ext/issues&quot;&gt;Please open an issue on GitHub if you&amp;#39;d like other datatypes supported that aren&amp;#39;t currently&lt;/a&gt;.
Since we can now add these columns via Rails migrations, and have
INET/CIDR and array columns converted to Ruby &lt;code&gt;IPAddr&lt;/code&gt; and &lt;code&gt;Array&lt;/code&gt;
objects, resepectively.&lt;/p&gt;

&lt;p&gt;Rails 4.0 has also added support for CIDR, INET, MACADDR and array
datatypes.&lt;/p&gt;

&lt;p&gt;It would be great if we could take advantage of
PostgreSQL&amp;#39;s query support for these datatypes. Wait, we can already do
that!&lt;/p&gt;

&lt;h2&gt;Querying against arrays using &lt;code&gt;ANY&lt;/code&gt; and &lt;code&gt;ALL&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;In PostgreSQL, you can query for records where any or all elements match
a given predicate.&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; *
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; users
&lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;johnny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; = &lt;span class=&quot;keyword&quot;&gt;ANY&lt;/span&gt;(nicknames)
&lt;span class=&quot;comment&quot;&gt;-- Finds any record that has &#39;johnny&#39; stored in the nicknames array&lt;/span&gt;

&lt;span class=&quot;class&quot;&gt;SELECT&lt;/span&gt; *
&lt;span class=&quot;keyword&quot;&gt;FROM&lt;/span&gt; user_scores
&lt;span class=&quot;keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;integer&quot;&gt;1000&lt;/span&gt; &amp;gt; &lt;span class=&quot;keyword&quot;&gt;ALL&lt;/span&gt;(scores)
&lt;span class=&quot;comment&quot;&gt;-- Finds any record that has over 1000 stored in every element in the&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;-- scores array&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We can actually use arel to generate these queries.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;user_arel = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.arel_table

any_nicknames_function = &lt;span class=&quot;constant&quot;&gt;Arel&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Nodes&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;NamedFunction&lt;/span&gt;.new(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ANY&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, [user_arel[&lt;span class=&quot;symbol&quot;&gt;:nicknames&lt;/span&gt;]])
predicate = &lt;span class=&quot;constant&quot;&gt;Arel&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Nodes&lt;/span&gt;::Equality(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, any_nicknames_function)

sql_statement = user_arel.project(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).where(predicate).to_sql
&lt;span class=&quot;comment&quot;&gt;#=&amp;gt; SELECT * FROM \&amp;quot;users\&amp;quot; WHERE &#39;test&#39; = ANY(\&amp;quot;users\&amp;quot;.\&amp;quot;nicknames\&amp;quot;)&lt;/span&gt;

users_with_nickname = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.find_by_sql(sql_statement)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the above example, we have to create an &lt;code&gt;Equality&lt;/code&gt; node manually
since the left hand side of the predicate is the value, instead of the
column. If you need &lt;code&gt;&amp;lt;&lt;/code&gt; in your predicate, you would create a &lt;code&gt;LessThan&lt;/code&gt;
node instead of an equality node.&lt;/p&gt;

&lt;p&gt;This example applies to both Rails 3.2+ with postgres_ext and Rails 4.0
with native array support.&lt;/p&gt;

&lt;h2&gt;Array overlap&lt;/h2&gt;

&lt;p&gt;In PostgreSQL, you can check if two arrays have one or more elements in
common by using the overlap operator, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{1,2,3}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{4,5,6}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;-- f&lt;/span&gt;
&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{1,2,3}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{3,4}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;-- t&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In postgres_ext, I added a new Arel predicate node for the 
overlap operator.  For the time being, it is named &lt;code&gt;ArrayOverlap&lt;/code&gt;
and can be called from a &lt;code&gt;Arel::Attribute&lt;/code&gt; as &lt;code&gt;#array_overlap&lt;/code&gt;. It
is likely that this will be renamed to &lt;code&gt;Overlap&lt;/code&gt; and &lt;code&gt;#overlap&lt;/code&gt;,
respectively, in the next release of postgres_ext.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;user_arel = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.arel_table

&lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.where(user_arel[&lt;span class=&quot;symbol&quot;&gt;:tags&lt;/span&gt;].array_overlap([&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;])).to_sql
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; SELECT \&amp;quot;users\&amp;quot;.* FROM \&amp;quot;users\&amp;quot; WHERE \&amp;quot;users\&amp;quot;.\&amp;quot;tags\&amp;quot; &amp;amp;&amp;amp; &#39;{one,two}&#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;One case that we have used an array column in tandem with the overlap
operator was adding tags to a user. We had three tags that could be
placed on a user, so we stored this data an array column. We then had a
search form which had a multiselect field for that tags column. The
multiselect would give us an array of possible values that we wanted to
find records that had any of those selected values. So instead of
crafting a statement with multiple &lt;code&gt;ANY&lt;/code&gt; queries &lt;code&gt;OR&lt;/code&gt;ed together, we
used overlap instead, resulting in only one predicate.&lt;/p&gt;

&lt;h2&gt;INET/CIDR subnet inclusion&lt;/h2&gt;

&lt;p&gt;In PostgreSQL, you can see if a particular INET address is contained in
a specific subnet with the contained within operator, &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight sql &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;inet &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;192.168.1.6&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &amp;lt;&amp;lt; inet &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;10.0.0.0/24&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;-- f&lt;/span&gt;

inet &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;192.168.1.6&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &amp;lt;&amp;lt; inet &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;192.168.1.0/24&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;-- t&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In postgres_ext, I added a new Arel predicate node for the 
contained within operator. It can be called from a
&lt;code&gt;Arel::Attribute&lt;/code&gt; with &lt;code&gt;#contained_within&lt;/code&gt;. I also added a visitor for
IPAddr objects so that they are correctly converted to quoted strings
when called within a Arel predicate.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;user_arel = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.arel_table

&lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.where(user_arel[&lt;span class=&quot;symbol&quot;&gt;:ip_address&lt;/span&gt;].contained_within(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;10.0.0.0/8&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).to_sql
&lt;span class=&quot;comment&quot;&gt;#=&amp;gt; SELECT \&amp;quot;users\&amp;quot;.* FROM \&amp;quot;users\&amp;quot; WHERE \&amp;quot;users\&amp;quot;.\&amp;quot;ip_address\&amp;quot; &amp;lt;&amp;lt; &#39;10.0.0.0/8&#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;We&amp;#39;re not done yet&lt;/h2&gt;

&lt;p&gt;We have only scratched the surface of the datatype specific functions
and operators in PostgreSQL. There are many more to be implemented, and
the plan is to support them all. This post highlights what has been
implemented so far, and also what you can do with Arel already. I plan
to put together some pull requests for Arel to add in some of the
PostgreSQL operators. If there is an operator missing in postgres_ext
that you want/need, please &lt;a href=&quot;https://github.com/dockyard/postgres_ext/issues?state=open&quot;&gt;open an issue on
Github&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Making of the DockYard Narwin</title>
    <link rel="alternate" href="https://dockyard.com/blog/design/2012/09/20/making-of-the-dockyard-narwin" />
    <id>https://dockyard.com/blog/design/2012/09/20/making-of-the-dockyard-narwin</id>
    <category term="design" label="Design"/>
    <published>2012-09-20 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Amanda Cheung</name></author>
    <summary>Animated gif of the evolution of the narwin</summary>
    <content type="html">&lt;p&gt;Half narwhal, half penguin. He&amp;#39;s a cute lil&amp;#39; fella with quite the personality. He set the stage for the redesign of our website while becoming DockYard&amp;#39;s new brand mascot.&lt;/p&gt;

&lt;p&gt;The Final Version:
&lt;img src=&quot;https://i.imgur.com/gadHFL4.jpg&quot; alt=&quot;DockYard&quot;&gt;&lt;/p&gt;

&lt;p&gt;The Evolution:
&lt;img src=&quot;https://i.imgur.com/dxjG83r.gif&quot; alt=&quot;DockYard Narwin&quot;&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Rails 4.0 Sneak Peek: PostgreSQL array support</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/09/18/rails-4-sneak-peek-postgresql-array-support" />
    <id>https://dockyard.com/blog/ruby/2012/09/18/rails-4-sneak-peek-postgresql-array-support</id>
    <category term="postgresql" label="PostgreSQL"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/>
    <published>2012-09-18 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Storing arrays natively in PostgreSQL is now supported by Rails</summary>
    <content type="html">&lt;p&gt;I&amp;#39;m happy to announce that &lt;a href=&quot;https://github.com/rails/rails/pull/7547&quot;&gt;Rails 4.0 now has support for PostgreSQL
arrays&lt;/a&gt;. You can create an
array column easily at the time of migration by adding &lt;code&gt;:array =&amp;gt; true&lt;/code&gt;.
Creating an array column will respect the other options you add to the
column (&lt;code&gt;length&lt;/code&gt;, &lt;code&gt;default&lt;/code&gt;, etc). &lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:table_with_arrays&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.integer &lt;span class=&quot;symbol&quot;&gt;:int_array&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# integer[]&lt;/span&gt;
  t.integer &lt;span class=&quot;symbol&quot;&gt;:int_array&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:length&lt;/span&gt; =&amp;gt; &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# smallint[]&lt;/span&gt;
  t.string &lt;span class=&quot;symbol&quot;&gt;:string_array&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:length&lt;/span&gt; =&amp;gt; &lt;span class=&quot;integer&quot;&gt;30&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# char varying(30)[]&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt; 
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It should be noted when setting the default value for an array column,
you should use PostgreSQL&amp;#39;s array notation for that value
(&lt;code&gt;{value,another value}&lt;/code&gt;). If you want the default value to be an empty
array you would have &lt;code&gt;:default =&amp;gt; &amp;#39;{}&amp;#39;&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:table_with_arrays&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.integer &lt;span class=&quot;symbol&quot;&gt;:int_array&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:default&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# integer[], default == []&lt;/span&gt;
  t.integer &lt;span class=&quot;symbol&quot;&gt;:int_array&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:length&lt;/span&gt; =&amp;gt; &lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:default&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{1}&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# smallint[], default == [1]&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt; 
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;An example of a model with an array value&lt;/h2&gt;

&lt;p&gt;Let&amp;#39;s say that we have a user model, which has a formal first and last
name, and also a number of nicknames (I rarely ever go by Daniel). The
following code would create the table we need to store this.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:users&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.string &lt;span class=&quot;symbol&quot;&gt;:first_name&lt;/span&gt;
  t.string &lt;span class=&quot;symbol&quot;&gt;:last_name&lt;/span&gt;
  t.string &lt;span class=&quot;symbol&quot;&gt;:nicknames&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And we have a simple model for this table:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;User&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  attr_accessible &lt;span class=&quot;symbol&quot;&gt;:first_name&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:last_name&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:nicknames&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Where we don&amp;#39;t have a default value, if we instantiate a User object
with the following&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;john = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.create(&lt;span class=&quot;symbol&quot;&gt;:first_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;John&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:last_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Doe&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If we call &lt;code&gt;john.nicknames&lt;/code&gt;, &lt;code&gt;nil&lt;/code&gt; would be returned, and is stored as
&lt;code&gt;NULL&lt;/code&gt; in PostgresSQL. We can set the nicknames attribute at the time of
creation with&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;john = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.create(&lt;span class=&quot;symbol&quot;&gt;:first_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;John&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:last_name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Doe&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,
  &lt;span class=&quot;symbol&quot;&gt;:nicknames&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Jack&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Johnny&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;])
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If we then retrieved this record from the database, the &lt;code&gt;nicknames&lt;/code&gt;
value would be casted to an array, instead of returning the string of
&lt;code&gt;{Jack,Johnny}&lt;/code&gt;.  Rails 4.0 has a pure ruby array value parser, but if
you would like to speed up the parsing process, the previously mentioned
&lt;a href=&quot;https://github.com/dockyard/pg_array_parser&quot;&gt;pg_array_parser&lt;/a&gt;
gem will be used if it is available. PgArrayParser has
a C extension, and a Java implementation for JRuby (although the gem
currently broken in JRuby, this is something I am fixing now).&lt;/p&gt;

&lt;p&gt;One important thing to note when interacting with array (or other
mutable values) on a model.  ActiveRecord does not currently track
&amp;quot;destructive&amp;quot;, or in place changes. These include array &lt;code&gt;push&lt;/code&gt;ing and
&lt;code&gt;pop&lt;/code&gt;ing, &lt;code&gt;advance&lt;/code&gt;-ing DateTime objects. If you want to use a
&amp;quot;destructive&amp;quot; update, you must call &lt;code&gt;&amp;lt;attribute&amp;gt;_will_change!&lt;/code&gt; to let
ActiveRecord know you changed that value. With our User model, if we
wanted to append a nickname, you can do the following:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;john = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.first

john.nicknames += [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Jackie boy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;]
&lt;span class=&quot;comment&quot;&gt;# or&lt;/span&gt;
john.nicknames = john.nicknames.push(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Jackie boy&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;comment&quot;&gt;# Any time an attribute is set via `=`, ActiveRecord tracks the change&lt;/span&gt;
john.save

john.reload
john.nicknames
&lt;span class=&quot;comment&quot;&gt;#=&amp;gt; [&#39;Jack&#39;, &#39;Johnny&#39;, &#39;Jackie Boy&#39;]&lt;/span&gt;

john.nicknames.pop
john.nicknames_will_change!
&lt;span class=&quot;comment&quot;&gt;# &#39;#pop&#39; changes the value in place, so we have to tell ActiveRecord it changed&lt;/span&gt;
john.save
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;One last note about arrays in PostgreSQL: there are no element count
constraints, and any array can be multidimensional. With the
multidimensional arrays, they must be &amp;quot;square&amp;quot; (the sub arrays must all
have the same number of elements).&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;[[&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;], [&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt;], [&lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;5&lt;/span&gt;,&lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;]]
&lt;span class=&quot;comment&quot;&gt;# Valid array value in PostgreSQL, each subarray has the same number of&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;# elements&lt;/span&gt;
[&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;,[&lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;4&lt;/span&gt;]]
&lt;span class=&quot;comment&quot;&gt;# Invalid array, we are mixing values and arrays at a single level&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In my next article, I will talk about querying PostgreSQL arrays in both
postgres_ext and Rails 4.0. Go forth and use arrays in Rails 4.0!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Doug Yun is a DockYarder!</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2012/09/05/doug-yun-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2012/09/05/doug-yun-is-a-dockyarder</id>
    <category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2012-09-05 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>DockYard welcomes Doug Yun</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/netbX9E.png&quot; alt=&quot;Doug Yun&quot;&gt;&lt;/p&gt;

&lt;p&gt;Doug has been training with us for the past month and this week we&amp;#39;ve
released him from his cage on the nearest client app. He&amp;#39;s running wild!&lt;/p&gt;

&lt;p&gt;This rounds out our Boston team to 4! ZOMG!&lt;/p&gt;

&lt;p&gt;Follow him on the &lt;a href=&quot;http://twitter.com/DougYun&quot;&gt;Twitters&lt;/a&gt; and
&lt;a href=&quot;https://github.com/duggieawesome&quot;&gt;github&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Lessons Learned: The First Hire</title>
    <link rel="alternate" href="https://dockyard.com/blog/opinion/2012/08/30/lessons-learned-the-first-hire" />
    <id>https://dockyard.com/blog/opinion/2012/08/30/lessons-learned-the-first-hire</id>
    <category term="opinion" label="Opinion"/><category term="business" label="Business"/>
    <published>2012-08-30 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>What to expect when you start hiring</summary>
    <content type="html">&lt;p&gt;In February we made our first full-time hire with Dan McClain. He came
on board at a time when our company was not very stable but we needed to
grow to accomodate the larger contracts we wanted. I want to discuss the
risks and benefits on making the first hire.&lt;/p&gt;

&lt;h2&gt;You will lose money&lt;/h2&gt;

&lt;p&gt;One of the first things you learn about making your first full-time hire
beyond the founders is that you will most likely lose money. Which is
kind of backwards because the entire point of hiring is so more money
can be made. Brian Kaney at &lt;a href=&quot;http://vermonster.com&quot;&gt;Vermonster&lt;/a&gt; told me this after we had already
hired Dan. I was accustomed to balancing 3 people&amp;#39;s salaries and now a
4th was in play and we didn&amp;#39;t have any extra money coming in. So we the
partners had to take less money. After Brian told me that Vermonster had
similar growing pains it made me feel better. I&amp;#39;ve since spoken with
others that have said the same. I suspect this is partly due to my
inexperience as a first time business owner, if I ever start another
company I can plan better for this. It is also due simply to the fact
that we didn&amp;#39;t have any extra work coming in and were now dividing the
money 4 ways instead of 3. The employees have to be paid, the partners
don&amp;#39;t. I took on the brunt of the risk and actually just started paying
myself for the first time in 2012 at the start of August. It was totally
worth it.&lt;/p&gt;

&lt;h2&gt;Be picky who you hire&lt;/h2&gt;

&lt;p&gt;I&amp;#39;d like to say that Dan hired himself rather than we hired him. He was
somewhat new to the Boston Ruby community but was going out of his way
to make himself known. He took the initiative to introduce himself to
me and wanted to make contributions to the &lt;a href=&quot;https://github.com/bostonrb/bostonrb&quot;&gt;BostonRB website&lt;/a&gt;.
He developed a feature, made a pull request, and I gave him feedback.
What impressed me was how quickly he adapted to the feedback I gave him.
This told me one thing: Dan was a very quick learner. Before DockYard
was even looking to hire Dan contacted me and expressed interest in
being hired. When it came time for us to make a hire he was the first
name that came to mind. I think the lesson to learn here is if you want
to work somewhere, don&amp;#39;t wait for them to hire for your talent. Contact
them, let them know you are interested even if they don&amp;#39;t have anything
available. When the time comes they&amp;#39;ll remember you.&lt;/p&gt;

&lt;h2&gt;Make full-time hires, don&amp;#39;t contract to hire&lt;/h2&gt;

&lt;p&gt;We hired Dan on a contract-to-hire basis. The idea at the time was to
have Dan on a &amp;quot;trial&amp;quot; period, test him out, see how he fit. I didn&amp;#39;t
like how this went and I don&amp;#39;t think it was fair to Dan to hire this
way. If you are hiring for a position, hire full-time. If things aren&amp;#39;t
working out you are always within your rights to let the person go.
Whenever you are hiring someone there is always the risk that it won&amp;#39;t
work out.&lt;/p&gt;

&lt;h2&gt;Be mindful of taxes, benefits, salaries, etc...&lt;/h2&gt;

&lt;p&gt;Now that we had our first full-time on board we had to standardize
everything. The best way to describe how I was handling all of this up
until our first hire is &amp;quot;half-assed&amp;quot;. I was the only one living in
Massachusetts where it was required to have health-care so I was using
the MA Health Connector (a terrible service), we were handling time-off
as &amp;quot;whenever you want&amp;quot; which of course doesn&amp;#39;t fly well as you scale,
and taxes were a mystery to me. Let&amp;#39;s break each one down to see what
we&amp;#39;ve done:&lt;/p&gt;

&lt;h3&gt;Benefits&lt;/h3&gt;

&lt;p&gt;I went for the best health-care I could find for employees. When it
comes down to it we&amp;#39;re only talking about the difference of a few hundred
dollars each month. If we go under because of this cost then I deserve
to lose my company. If one of my employees cannot see the doctor they
need to because of sub-standard health coverage I run the risk that they
will not be back to work as quickly as they would otherwise. This risk
costs far more than the extra $$$ for the better plans.&lt;/p&gt;

&lt;p&gt;DockYard is currently covering 3/4 of the healthcare and I hope to bring
that up to 100% in 2013.&lt;/p&gt;

&lt;p&gt;We&amp;#39;re doing 3 weeks of paid vacation per year. Employees can take off
two weeks at a time. I am also experimenting with how to handle
overtime. Because we&amp;#39;re doing client work and sometimes deadlines have
to be met I&amp;#39;ve told everyone that there will be a day when they get
Lumberged. I&amp;#39;m going to be the guy that will have to ask people to work
over a weekend, I don&amp;#39;t like it and I would be pissed if I was on the
receiving end of that. So, to compensate we&amp;#39;ll offer an added vacation
day in exchange for each weekend day. Of course employees can say &amp;quot;no&amp;quot;
to working on the weekend. I understand that there are sometimes plans
that are made well in advance.&lt;/p&gt;

&lt;h3&gt;Payroll&lt;/h3&gt;

&lt;p&gt;This is something we have struggled with. Everyone has always been paid
but sometimes it has been a day late because of mistakes on my part.
Originally I was cutting checks to everyone and mailing them myself. I
would manually enter the data into QuickBooks for our accountant. This
sucks. I eventually got it down to where it would only take me 5 minutes
to do but for a while it was pretty disruptive. We eventually moved over
Direct Deposit through QuickBooks. This was much better, and quicker. If
you are not doing Direct Deposit you should highly consider it.&lt;/p&gt;

&lt;p&gt;We&amp;#39;ve recently moved from QuickBooks to Less Accounting and Sure
Payroll. QuickBooks blows. We only used it because our accountant
suggested it. Here is some advice: don&amp;#39;t let your accountant make
software decisions for you, especially if you are a software
consultancy. Our accountant is awesome, but QuickBooks is not. We lost
an entire month of payroll, tax, and vendor payment data because a
QuickBooks file corrupted. Never again.&lt;/p&gt;

&lt;h3&gt;Salaries, taxes&lt;/h3&gt;

&lt;p&gt;One &lt;em&gt;huge&lt;/em&gt; mistake I made even before hiring Dan but continued into a
month after he was hired was not withholding taxes from paychecks. We
were losing money after our first quarterly taxes were paid and I couldn&amp;#39;t figure it out. In retrospect it is
pretty obvious what I should have been doing but keep in mind this was
my first company, I never had to deal with this before, and simply
fucked up. Things turned around after I corrected this. I didn&amp;#39;t ask for
employees to payback the money. I&amp;#39;m not trying to push this idea that
I&amp;#39;m a &amp;quot;good guy&amp;quot; but this was my screw up and I took the hit.&lt;/p&gt;

&lt;p&gt;Also, pay people well. &amp;quot;Industry average salary&amp;quot; will earn you &amp;quot;industry
average employees&amp;quot;. If it is well known that you are paying high
salaries you will attract talented people. Talented people will more
than make up the difference.&lt;/p&gt;

&lt;h2&gt;Hiring ain&amp;#39;t easy&lt;/h2&gt;

&lt;p&gt;I&amp;#39;ve heard the term &amp;quot;peak people&amp;quot; thrown around a lot recently. It
refers to the huge talent shortage that the tech industry has. It&amp;#39;s
true, it exists. You know why? Because everybody wants to hire top
talent and nobody wants to train. I think it is pretty bullshit for
companies to not train developers. Personally I would rather hire a
developer that requires training that is a quick learner than hire a
mid-level dev that is set in his/her ways. We got lucky with Dan, he
required very little ramping up. Mostly just a push here and a push
there. We&amp;#39;ve recently hired Doug Yun as a trainee. I told Doug that we
are experimenting with him, I want to establish a training program at
DockYard. So there will be ups and downs to it as we establish a
playbook. I realize we run the risk of devs training up, then bouncing
out. There are ways to address this. We can offer employment term
benefits. If you are at DockYard for a year your salary will increase by
X% every year. Let them know what the path for advancement is. We need
to get better at this and it is something I want to focus on over the next
few months. I would love to hear feedback and how others are
approaching this.&lt;/p&gt;

&lt;h2&gt;It pushes you to make things happen&lt;/h2&gt;

&lt;p&gt;The best benefit of hiring is that it personally motivates me to grow
the company. When it was just the co-founders we always had the fallback 
that a payroll period could be skipped. As I mentioned earlier that is
not a choice when you have employees. Money must come in, people must
get paid. Personally I have found this to be a good motivator for
growing DockYard.&lt;/p&gt;

&lt;h2&gt;Share your experiences!&lt;/h2&gt;

&lt;p&gt;If you agree/disagree with anything I said, have a different
perspective, or any general advice I&amp;#39;d love to hear it.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Rails 4.0 Sneak Peek: Asynchronous ActionMailer</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/06/26/rails-4-sneak-peek-async-actionmailer" />
    <id>https://dockyard.com/blog/ruby/2012/06/26/rails-4-sneak-peek-async-actionmailer</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/>
    <published>2012-06-26 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>How to send your emails using the new Rails 4.0 Queue</summary>
    <content type="html">&lt;p&gt;My previous &lt;a href=&quot;http://reefpoints.dockyard.com/ruby/2012/06/25/rails-4-sneak-peek-queueing.html&quot;&gt;deep dive into the Rails 4.0 Queueing system&lt;/a&gt;
 was motivated by a patch to Rails I was working on while at &lt;a href=&quot;http:/railscamps.org&quot;&gt;RailsCamp New England&lt;/a&gt; this past weekend. I&amp;#39;m happy to say that &lt;a href=&quot;https://github.com/rails/rails/pull/6839&quot;&gt;Rails 4.0 now has an optional asynchronous ActionMailer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The API for pushing your emails to the background is very simple. If you
want to make this change application wide simply set it in your
&lt;code&gt;application.rb&lt;/code&gt; (or in any of the environment files)&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;config.action_mailer.async = &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Or if you want to only make specific mailers asynchrounous&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;WelcomeMailer&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActionMailer&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;predefined-constant&quot;&gt;self&lt;/span&gt;.async = &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That&amp;#39;s it! Any messages that are being delivered will be sent as a
background job. In fact, the rendering is happening on the background as
well.&lt;/p&gt;

&lt;p&gt;You will need to take care that the arguments you are passing your
mailers can be properly marshalled. Instead of:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;WelcomeMailer&lt;/span&gt;.welcome(&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;).deliver
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You should do:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;WelcomeMailer&lt;/span&gt;.welcome(&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.id).deliver
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then in your mailer:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;WelcomeMailer&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActionMailer&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;welcome&lt;/span&gt;(id)
    &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.find(id)
    ...
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Switching it up&lt;/h2&gt;

&lt;p&gt;The default queueing system is &lt;code&gt;Rails.queue&lt;/code&gt;, but you can override this to use any queueing system you
want by overriding &lt;code&gt;ActionMailer::Base#queue&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;WelcomeMailer&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActionMailer&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;queue&lt;/span&gt;
    &lt;span class=&quot;constant&quot;&gt;MyQueue&lt;/span&gt;.new
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Your custom queue should expect the jobs to respond to &lt;code&gt;#run&lt;/code&gt;, same as
&lt;code&gt;Rails.queue&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Credit&lt;/h2&gt;

&lt;p&gt;Much of the original code was cribbed (with permission) from &lt;a href=&quot;http://blog.zerosum.org&quot;&gt;Nick
Plante&lt;/a&gt;&amp;#39;s
&lt;a href=&quot;https://github.com/zapnap/resque_mailer&quot;&gt;resque_mailer&lt;/a&gt; gem.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Rails 4.0 Sneak Peek: Queueing</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/06/25/rails-4-sneak-peek-queueing" />
    <id>https://dockyard.com/blog/ruby/2012/06/25/rails-4-sneak-peek-queueing</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/>
    <published>2012-06-25 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A look at the new Queueing API</summary>
    <content type="html">&lt;p&gt;Recently a &lt;a href=&quot;https://github.com/rails/rails/commit/adff4a706a5d7ad18ef05303461e1a0d848bd662&quot;&gt;queueing system was added to Rails&lt;/a&gt;.
Let&amp;#39;s dive in and see how to use it.&lt;/p&gt;

&lt;h2&gt;Run, baby, run!&lt;/h2&gt;

&lt;p&gt;The queueing API is very simple. You push an object on to the queue and
that object is expected to respond to a &lt;code&gt;run&lt;/code&gt; method. Let&amp;#39;s take a look:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;TestJob&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;run&lt;/span&gt;
    puts &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am running!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;constant&quot;&gt;Rails&lt;/span&gt;.queue.push(&lt;span class=&quot;constant&quot;&gt;TestJob&lt;/span&gt;.new)
=&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am running!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For most people, that is pretty much it. The queue is running in a
separate thread from the app thread, so your app shouldn&amp;#39;t notice any
response impact from an expensive job.&lt;/p&gt;

&lt;p&gt;The basic queue that comes with Rails is not a long-term solution. The
goal here is to establish a common API that more robust queueing systems
can plug themselves into. In most cases you shouldn&amp;#39;t need to change any
of your app code if you want to switch from
&lt;a href=&quot;https://github.com/defunkt/resque&quot;&gt;Resque&lt;/a&gt; to
&lt;a href=&quot;https://github.com/mperham/sidekiq&quot;&gt;Sidekiq&lt;/a&gt;. You should take care that
the objects you are enqueing can be properly marshalled.&lt;/p&gt;

&lt;p&gt;You can even write your own queue, let&amp;#39;s take a look at the API of a
custom queue&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;MyQueue&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;push&lt;/span&gt;(job)
    job.run
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then in your &lt;code&gt;application.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;config.queue = &lt;span class=&quot;constant&quot;&gt;MyQueue&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This example is straight from the Rails test suite. This will define a
queue that does not run jobs asynchronously. As soon as the job is
pushed onto the queue it is run. Let&amp;#39;s make an actual queue (without relying on
the Queue class)&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;MyQueue&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@queue&lt;/span&gt; = []
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;push&lt;/span&gt;(job)
    &lt;span class=&quot;instance-variable&quot;&gt;@queue&lt;/span&gt;.push(job)
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;pop&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@queue&lt;/span&gt;.pop
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In this example we have implemented a simple queue. You will next need
to tell Rails&amp;#39;s QueueConsumer to use this queue. You can do this in
&lt;code&gt;application.rb&lt;/code&gt; with an initializer block:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;intializer &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;start queue consumer&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |app|
  app.queue_consumer = config.queue_consumer.start(app.queue)
  at_exit { app.queue.consumer.shutdown }
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;and if we now push to our new queue:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Rails&lt;/span&gt;.queue.push(&lt;span class=&quot;constant&quot;&gt;TestJob&lt;/span&gt;.new)
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;...we get nothing. Why? Inspect the QueueConsumer:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Rails&lt;/span&gt;.application.queue_consumer
=&amp;gt; &lt;span class=&quot;comment&quot;&gt;#&amp;lt;Rails::Queueing::ThreadedConsumer @queue=#&amp;lt;MyQueue @queue=[]&amp;gt;, @thread=#&amp;lt;Thread dead&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;So you&amp;#39;ll notice that the thread is &lt;code&gt;dead&lt;/code&gt;. We can force the queue to
process by doing:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Rails&lt;/span&gt;.application.queue_consumer.start
=&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am running!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s back up to understand what is going on here. First we&amp;#39;ll start by looking at &lt;code&gt;ThreadedConsumer#start&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;start&lt;/span&gt;
  &lt;span class=&quot;instance-variable&quot;&gt;@thread&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;Thread&lt;/span&gt;.new &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; job = &lt;span class=&quot;instance-variable&quot;&gt;@queue&lt;/span&gt;.pop
      &lt;span class=&quot;keyword&quot;&gt;begin&lt;/span&gt;
        job.run
      &lt;span class=&quot;keyword&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;constant&quot;&gt;Exception&lt;/span&gt; =&amp;gt; e
        handle_exception e
      &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;predefined-constant&quot;&gt;self&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;So this thread is only staying alive as long as the &lt;code&gt;@queue.pop&lt;/code&gt; returns a truthy value.
It&amp;#39;s not reasonable or us to keep shoving something into the queue, so let&amp;#39;s see what is happening 
in &lt;code&gt;Queue#pop&lt;/code&gt;. For this we&amp;#39;ll look at Rubinius&amp;#39; implementation&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# Retrieves data from the queue.  If the queue is empty, the calling thread is&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;# suspended until data is pushed onto the queue.  If +non_block+ is true, the&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;# thread isn&#39;t suspended, and an exception is raised.&lt;/span&gt;
&lt;span class=&quot;comment&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;pop&lt;/span&gt;(non_block=&lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;)
  &lt;span class=&quot;keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@mutex&lt;/span&gt;.synchronize &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;instance-variable&quot;&gt;@waiting&lt;/span&gt;.delete(&lt;span class=&quot;constant&quot;&gt;Thread&lt;/span&gt;.current)
      &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;instance-variable&quot;&gt;@que&lt;/span&gt;.empty?
        raise &lt;span class=&quot;constant&quot;&gt;ThreadError&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;queue empty&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; non_block
        &lt;span class=&quot;instance-variable&quot;&gt;@waiting&lt;/span&gt;.push &lt;span class=&quot;constant&quot;&gt;Thread&lt;/span&gt;.current
        &lt;span class=&quot;instance-variable&quot;&gt;@resource&lt;/span&gt;.wait(&lt;span class=&quot;instance-variable&quot;&gt;@mutex&lt;/span&gt;)
      &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;
        retval = &lt;span class=&quot;instance-variable&quot;&gt;@que&lt;/span&gt;.shift
        &lt;span class=&quot;instance-variable&quot;&gt;@resource&lt;/span&gt;.signal
        &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; retval
      &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This now starts to make sense. &lt;code&gt;Queue#pop&lt;/code&gt; is an infinite loop that will wait until it has
content before each iteration. Our simple &lt;code&gt;MyQueue&lt;/code&gt; class would return &lt;code&gt;nil&lt;/code&gt; when &lt;code&gt;ThreadConsumer#start&lt;/code&gt;
is called because there is nothing in the queue and the thread would die. Even if we put something in
queue it would pop once, run the job, try to pop againg, then die.&lt;/p&gt;

&lt;p&gt;For the sake of simplicity let&amp;#39;s just have &lt;code&gt;MyQueue&lt;/code&gt; inherit from
&lt;code&gt;Queue&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;MyQueue&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Queue&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we can run&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Rails&lt;/span&gt;.queue.push(&lt;span class=&quot;constant&quot;&gt;TestJob&lt;/span&gt;.new)
=&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;I am running!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The queue system in Rails 4.0 is a very simple solution, I&amp;#39;m looking
forward to the release and the support for it to be added to many of the
leading background job processing libraries.&lt;/p&gt;

&lt;p&gt;Keep in mind that as of this writing the master branch is still
versioned as &amp;#39;beta&amp;#39;. This API could change.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Lessons Learned: The First Six Months of Running a Software Consultancy</title>
    <link rel="alternate" href="https://dockyard.com/blog/opinion/2012/06/21/lessons-learned-six-month-of-running-dockyard" />
    <id>https://dockyard.com/blog/opinion/2012/06/21/lessons-learned-six-month-of-running-dockyard</id>
    <category term="consulting" label="Consulting"/><category term="opinion" label="Opinion"/><category term="business" label="Business"/>
    <published>2012-06-21 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Brian talks about what has worked, what has not worked, and the changes that have been made at DockYard during its first six month</summary>
    <content type="html">&lt;p&gt;Before I get into it, I&amp;#39;m writing this because when I was first setting
out with DockYard there was little to no guidance. It seems that most
agencies are hush-hush on how they work internally. Or I just suck at
the Googles. In any event, I wanted to share our experience in the hope
that others can learn and give feedback.&lt;/p&gt;

&lt;h2&gt;Clients&lt;/h2&gt;

&lt;p&gt;Be selective! If your gut tells you something is wrong listen to it. I
made a huge mistake with taking our very first client and an even bigger
mistake about re-signing with said client. It ended ugly, I always felt
it might. The client was bad (no I won&amp;#39;t say who it was) and it really
put us in a very difficult position when we were getting started. I went
back to re-sign because the first contract ended in December. It turns
out December is a &lt;em&gt;terrible&lt;/em&gt; month for finding new work. I panicked,
rookie move. Thankfully we have had great clients since. That&amp;#39;s not to
say we haven&amp;#39;t had to dodge potentially bad clients from time to time.&lt;/p&gt;

&lt;p&gt;Some clients are just bad, but many are just &amp;quot;bad for us&amp;quot;. Those two
statements are very different and recognizing the difference is
important. &amp;quot;Bad for us&amp;quot; clients might be fantasic people but the
projects aren&amp;#39;t in our wheel house, in those cases I try my best to help
those people find other consultancies/freelancers.&lt;/p&gt;

&lt;h2&gt;Employees&lt;/h2&gt;

&lt;h3&gt;Salary&lt;/h3&gt;

&lt;p&gt;DockYard started as bringing together three freelance developers. The
first mistake I made was not insisting that everyone start on fulltime
salary. We were still paying out the full hourly rates then paying taxes
on top of that. Needless to say, accounting is not my strong point. It
took 2 months before I figured out why we weren&amp;#39;t making any money.
Whoops.&lt;/p&gt;

&lt;h3&gt;Process&lt;/h3&gt;

&lt;p&gt;I&amp;#39;ve changed from the &amp;quot;anything goes&amp;quot; type boss to the &amp;quot;I&amp;#39;m going to be
the hard-ass&amp;quot; over the past six months. Here is why: we want to balance
multiple projects. Finding a client that has enough of a budget for a 6
person team is great but not very likely if we stick with startups. So
our team sizes are small, but we need to be redundant. I tell everyone
on my team that they &amp;quot;need to be replacable&amp;quot;. Don&amp;#39;t take this statement
the wrong way, I&amp;#39;m clear that this doesn&amp;#39;t mean they&amp;#39;re getting canned
at the drop of a hat. It means that I don&amp;#39;t want to be in a position
where someone gets sick, goes on vacation, or leaves for another
opportunity and we plug someone else into that project and it takes that
person a week to ramp up because we need to figure out what the last
person was doing. &lt;em&gt;Process is very important&lt;/em&gt;, I would rather have good
developers that buy into our process than have awesome developers that
don&amp;#39;t. We function best as a team. So when someone isn&amp;#39;t buying into the
process we&amp;#39;ve been outlining I need to be the guy that says &amp;quot;no&amp;quot;. A few times this
has turned into debates, sometimes into arguments. I&amp;#39;m willing to modify
our process if something better is proposed but I&amp;#39;m not willing to
switch into the &amp;quot;just get it done&amp;quot;. At the start I avoided uncomfortable conversations, 
if something was happening that I didn&amp;#39;t think was right for DockYard I would wait it out.
This was a bad idea, the best time to correct something is now. Today I 
am jumping on these things immediately. I would rather have an airing of grievances 
when the issue is small rather than let it blow up.&lt;/p&gt;

&lt;p&gt;Here are some things that, arguably, are
&lt;a href=&quot;http://en.wikipedia.org/wiki/Parkinson&amp;#x27;s_Law_of_Triviality&quot;&gt;bikeshedding&lt;/a&gt;
but I have been insisting on:&lt;/p&gt;

&lt;h3&gt;The trivial&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Whitespace&lt;/li&gt;
&lt;li&gt;Single quotes instead of double quotes&lt;/li&gt;
&lt;li&gt;Verbose variable names&lt;/li&gt;
&lt;li&gt;Consistency between backend model names and HTML markup class names&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;The important&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Code quality&lt;/li&gt;
&lt;li&gt;CoffeeScript&lt;/li&gt;
&lt;li&gt;File/class naming conventions and organization&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Remotes&lt;/h3&gt;

&lt;p&gt;We started as entirely remote team. Angelo in Rhode Island, Russ in
Maine, and myself in Boston. This is OK but I must admit I&amp;#39;m not a big
fan of this. We have been hiring in Boston and will continue to grow a
team here.&lt;/p&gt;

&lt;h2&gt;Rates&lt;/h2&gt;

&lt;p&gt;We originally started at $120/hour. We have since moved to a flat
$4,000/week per developer. This buys the client about 32 hours of our
time.
This has been the single best change we&amp;#39;ve made. Keeping track of every
hours sucks, and I had to be on everyone&amp;#39;s ass making sure they got
their hours in. Now it is pretty simple. The clients also prefer this
system of invoicing, especially many of the large enterprise type
clients we are looking to go after.&lt;/p&gt;

&lt;p&gt;That being said, I think our rate is below our market value. I&amp;#39;ve spoken
with many other consultancies and the average seems to be $6k - 7k per
week for full stack (which we are). We are planning on raising our rates
to $5k in September then hopefully up to $6k by next year. It&amp;#39;s not that
I don&amp;#39;t think we are technically qualified to justify those rates yet,
its that I want to build out our portfolio first.&lt;/p&gt;

&lt;p&gt;I&amp;#39;ve noticed that many people don&amp;#39;t want to talk about money. I actually
don&amp;#39;t mind it, to the point that some people might find it annoying. In
order for the market to adjust properly I think an open discussion on
rates is necessary.&lt;/p&gt;

&lt;p&gt;I have also started telling potential clients our minimum project budget
($30k) before we get into any details of the engagement. Some might find
this off-putting. Here is my perspective: the client&amp;#39;s time is valuable
and I don&amp;#39;t want to waste their time. In most cases budget is a deciding
factor, let&amp;#39;s get that out into the open immediately rather than dealing
with surprises a month from now.&lt;/p&gt;

&lt;p&gt;We have reduced our rates to work on interesting projects. We&amp;#39;re nearly
done with a real-time chat app using an EventMachine backend with a
websocket front end. That was a fun one to build, we reduced our rate by
17% because of the client&amp;#39;s limited budget.&lt;/p&gt;

&lt;h2&gt;Business Development&lt;/h2&gt;

&lt;p&gt;This is something I have learned as I go. Not to toot my own horn but I
believe one of my strengths is selling DockYard as a business to
potential clients. Finding new clients has not been easy. Here are some
things that led directly to client contact (sorted by most effective):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing blog posts&lt;/li&gt;
&lt;li&gt;Giving presentations to general tech audiences (more beginners than
experts)&lt;/li&gt;
&lt;li&gt;LinkedIn&lt;/li&gt;
&lt;li&gt;Referrals&lt;/li&gt;
&lt;li&gt;Being found on Google&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LinkedIn?? Yeah, it actually worked. But I did something incredibly
douchey. I modified my LinkedIn profile to basically be an ad for
DockYard then I went to LinkedIn&amp;#39;s &amp;quot;People you may know&amp;quot; page and
clicked on over a thousand people. I got flagged for spamming but it
worked. Yes, I know it was a huge douchebag move. However, I suspected
that people would look at my profile to see if they knew me, or wanted
to be connected. If they happened to have a development need they would
contact me, if they didn&amp;#39;t they wouldn&amp;#39;t. At the very least I was
exposing DockYard to many people. I went from less than 100 LinkedIn
connections to close to 1000 in a week. We got two contracts from doing
this, it was worth it.&lt;/p&gt;

&lt;p&gt;Here are things that have not worked for us (yet)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running Community Events&lt;/li&gt;
&lt;li&gt;Sponsoring&lt;/li&gt;
&lt;li&gt;Open Source Development (see the comments for some interesting debate on this topic)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I organize &lt;a href=&quot;http://bostonrb.org&quot;&gt;BostonRB&lt;/a&gt;, it is one of the largest
Ruby user groups in the world. We have awesome speakers every month.
Every now and then when I talk shop with someone about work I get the
&amp;quot;I&amp;#39;m sure running BostonRB doesn&amp;#39;t hurt&amp;quot; with a wink. I find this
annoying. I&amp;#39;ve gone out of my way to make sure BostonRB doesn&amp;#39;t get
co-opted by any one company for promotional purposes. There is another
&amp;quot;Boston Rails Meetup&amp;quot; in Newton, MA that is essentially used to boost
SEO for another consultancy. I think this is bullshit. I&amp;#39;ll say it right
now: We have never been contacted by a client because of running
BostonRB. I&amp;#39;m not saying I would turn any down, but in my experience
running a user group is not driving clients to us.&lt;/p&gt;

&lt;p&gt;Now that I&amp;#39;m getting off my soapbox in the upcoming months DockYard will
be listed as a Sponsor for BostonRB, along with every other company that
is donating time, pizza, meeting space, etc...&lt;/p&gt;

&lt;p&gt;I&amp;#39;m a huge advocate for Open Source Development, but it also has very
poor ROI if your goal is to get clients. I believe there is a threshold
for this, if you&amp;#39;re on a certain tier (i.e. core committer to a popular
framework) it might be different.&lt;/p&gt;

&lt;h2&gt;Targeting Startups&lt;/h2&gt;

&lt;p&gt;On any given day people will hear me complain about startups. By their
very definition startups don&amp;#39;t have money. As a consultancy we are
looking to make money by engaging clients. If anybody tells you they&amp;#39;re
consulting because it is their passion or work with startups, they are
full of shit. This is a cash game. Demand is at an all time high, there
is a lot of opportunity to do well and work for yourself. While some of
the technology challenges startups present are very interesting I am
also running a business. This is why we have begun to favor enterprise.
We can get longer term contracts and these companies pay on time. The
downside is the technology is not terribly interesting.&lt;/p&gt;

&lt;p&gt;We are striving to find a balance here. I would be interested in hearing
others experience.&lt;/p&gt;

&lt;h2&gt;Doing Too Much&lt;/h2&gt;

&lt;p&gt;Right now I&amp;#39;m the guy wearing all of the hats. On any given day I&amp;#39;m
doign the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Biz development&lt;/li&gt;
&lt;li&gt;Marketing&lt;/li&gt;
&lt;li&gt;Lead Development&lt;/li&gt;
&lt;li&gt;Project Management&lt;/li&gt;
&lt;li&gt;Paying bills&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thankfully I haven&amp;#39;t burnt out yet but this cannot continue much longer.
The biggest mistake I have made over the first six months was not making
an early hire to take some of this load off. I must admit, this one
stumps me. I know how to hire a good developer, I know how to hire a
good designer. I have no idea how to hire for non-tech positions. We
have already hired a accountant to handle some of the larger items but
I&amp;#39;m still responsible for every day invoicing and book keeping. In my
mind, here are the priority hires:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Business developer. I have had light feelers out for this position
over the past few months. We really need someone focused on this
fulltime. Ideally someone that wants to hook into the startup community
in Boston or has existing sales relationships in the enterprise world.
Or if you happen to be in DC and have existing connection in the
political world we&amp;#39;d love to talk. &lt;a href=&quot;mailto:contact@dockyard.com&quot;&gt;Contact
us&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Office manager. We will be moving into our own space in the Fall. At
that time we will be looking to fill this position.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More developers and designers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Our Process&lt;/h2&gt;

&lt;p&gt;We have modified how to engage clients. This is what we are currently
doing&lt;/p&gt;

&lt;h3&gt;Initial Engagement&lt;/h3&gt;

&lt;p&gt;Phone call, get to know the client. Determine if we are a good fit. If
so and the client is happy with references, rate, etc... we move
forward.&lt;/p&gt;

&lt;h3&gt;Kick off&lt;/h3&gt;

&lt;p&gt;We charge for this. Currently it is $1000. We will sit down the client and
will run through what they want soup to nuts. We&amp;#39;ll have development and
design on hand for this meeting.&lt;/p&gt;

&lt;h3&gt;Design Phase&lt;/h3&gt;

&lt;p&gt;We originally combined development and design after the kickoff. This
was a mistake. There is a lot to be learned by doing an upfront design
phase. It helps us make informed estimations. The clients are happier
when we can deliver what we estimate. This phase we generally go for
wireframes and workflow. Nothing polished. We like to wireframe in
HTML/CSS.&lt;/p&gt;

&lt;h3&gt;Development Phase&lt;/h3&gt;

&lt;p&gt;Now that we have the general design worked out we begin development.
There will also be design done during this phase as well.&lt;/p&gt;

&lt;p&gt;I would love to hear about other processes. What works, what doesn&amp;#39;t
work.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I hope some peope find this information useful. Please feel free to ask
any questions or if you need me to elaborate on anything. If you feel
I&amp;#39;m off the mark or have suggestions feel free to comment as well. We&amp;#39;re
always looking to improve.&lt;/p&gt;
</content>
  </entry><entry>
    <title>postgres_ext: Adding Postgres data types to Rails</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/06/18/postgres_ext-adding-postgres-data-types-to-active-record" />
    <id>https://dockyard.com/blog/ruby/2012/06/18/postgres_ext-adding-postgres-data-types-to-active-record</id>
    <category term="gems" label="Gems"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="postgresql" label="PostgreSQL"/><category term="ruby" label="Ruby"/>
    <published>2012-06-18 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Announcing postgres_ext, a gem that adds support for PostgreSQL data types to ActiveRecord</summary>
    <content type="html">&lt;p&gt;Over the past few weeks, I have been working on a new gem which adds
support to Rail&amp;#39;s ActiveRecord for PostgreSQL&amp;#39;s native data types. I am
happy to announce that I have released the
&lt;a href=&quot;https://github.com/dockyard/postgres_ext&quot;&gt;postgres_ext&lt;/a&gt; gem.&lt;/p&gt;

&lt;p&gt;postgres_ext supports for ActiveRecord version 3.2 and above (at this
time). Parallel to my development, I plan to submit pull request to
Rails master, so that postgres_ext will not be needed in Rails 4.0.&lt;/p&gt;

&lt;h2&gt;Features&lt;/h2&gt;

&lt;h3&gt;Migration/Schema support&lt;/h3&gt;

&lt;p&gt;postgres_ext adds migration and &lt;code&gt;schema.rb&lt;/code&gt; support for the following
PostgresSQL type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;INET&lt;/li&gt;
&lt;li&gt;CIDR&lt;/li&gt;
&lt;li&gt;MACADDR&lt;/li&gt;
&lt;li&gt;UUID&lt;/li&gt;
&lt;li&gt;Arrays&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can create columns with the following migration methods:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:examples&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.inet &lt;span class=&quot;symbol&quot;&gt;:ip_address&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# INET Column&lt;/span&gt;

  t.cidr &lt;span class=&quot;symbol&quot;&gt;:subnet&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# CIDR Column&lt;/span&gt;

  t.macaddr &lt;span class=&quot;symbol&quot;&gt;:mac_address&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# MACADDR Column&lt;/span&gt;

  t.uuid &lt;span class=&quot;symbol&quot;&gt;:unique_id&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# UUID Column&lt;/span&gt;

  t.integer &lt;span class=&quot;symbol&quot;&gt;:int_array&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;comment&quot;&gt;# Integer[] Column&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;These migrations will be captured in your &lt;code&gt;schema.rb&lt;/code&gt; file, so you don&amp;#39;t
have to use the &lt;code&gt;structure.sql&lt;/code&gt; file if these types are your only reason. In
fact, if you are using these only supported types with &lt;code&gt;structure.sql&lt;/code&gt;,
including the postgres_ext gem should allow you to correctly &lt;code&gt;rake
db:schema:dump&lt;/code&gt; your database.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dockyard/postgres_ext#migrationschemarb-support&quot;&gt;Migration/Schema.rb support documentation&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Type Casting&lt;/h3&gt;

&lt;p&gt;postgres_ext converts INET and CIDR values to
&lt;a href=&quot;http://www.ruby-doc.org/stdlib-1.9.3/libdoc/ipaddr/rdoc/IPAddr.html&quot;&gt;IPAddr&lt;/a&gt; instances,
 and coverts arrays to array objects of the column type (integer arrays
are cast as an array of integers, INET arrays to are cast to an array of
IPAddrs).&lt;/p&gt;

&lt;h3&gt;INET Type Casting example&lt;/h3&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:inet_examples&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.inet &lt;span class=&quot;symbol&quot;&gt;:ip_address&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;InetExample&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

inetExample = &lt;span class=&quot;constant&quot;&gt;InetExample&lt;/span&gt;.new
inetExample.ip_address = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;127.0.0.0/24&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
inetExample.ip_address
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; #&amp;lt;IPAddr: IPv4:127.0.0.0/255.255.255.0&amp;gt;&lt;/span&gt;
inetExample.save

inet_2 = &lt;span class=&quot;constant&quot;&gt;InetExample&lt;/span&gt;.first
inet_2.ip_address
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; #&amp;lt;IPAddr: IPv4:127.0.0.0/255.255.255.0&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Array Type Casting example&lt;/h3&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:people&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.integer &lt;span class=&quot;symbol&quot;&gt;:favorite_numbers&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:array&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Person&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

person = &lt;span class=&quot;constant&quot;&gt;Person&lt;/span&gt;.new
person.favorite_numbers = [&lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;2&lt;/span&gt;,&lt;span class=&quot;integer&quot;&gt;3&lt;/span&gt;]
person.favorite_numbers
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; [1,2,3]&lt;/span&gt;
person.save

person_2 = &lt;span class=&quot;constant&quot;&gt;Person&lt;/span&gt;.first
person_2.favoite_numbers
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; [1,2,3]&lt;/span&gt;
person_2.favoite_numbers.first.class
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt; Fixnum&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dockyard/postgres_ext#type-casting-support&quot;&gt;Type casting documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Another gem born out of necessity&lt;/h2&gt;

&lt;p&gt;I have also released
&lt;a href=&quot;https://github.com/dockyard/pg_array_parser&quot;&gt;pg_array_parser&lt;/a&gt;, a C
extension which parses PostgreSQL array values and returns an array of
strings.  This gem is used by postgres_ext to retrieve the array values
before casting them to the required type.&lt;/p&gt;

&lt;h2&gt;Plans for postgres_ext&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://reefpoints.dockyard.com/ruby/2012/05/18/rails-4-sneak-peek-expanded-activerecord-support-for-postgresql-datatype.html&quot;&gt;INET, CIDR and MACADDR support has already been added to Rails 4.&lt;/a&gt;
My next step is to submit a pull request to add UUID migration support
and Array support to Rails master.  Then I plan to backport Rails 4&amp;#39;s
hstore support back to postgres_ext. After adding support for the other
PostgreSQL types, I plan to add support to arel for PostgreSQL type
specific where clauses (ie ANY for array comparison, &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; for
INET and CIDR comparisons.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Amanda Cheung is a DockYarder!</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2012/06/14/amanda-cheung-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2012/06/14/amanda-cheung-is-a-dockyarder</id>
    <category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2012-06-14 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>DockYard welcomes Amanda Cheung</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/mwQmXZ0.jpg&quot; alt=&quot;Amanda Cheung&quot;&gt;&lt;/p&gt;

&lt;p&gt;Yesterday was Amanda&amp;#39;s first day with DockYard, she joins our growing
team as a designer with a desire to develop. She brings excellent design
skills and much needed illustration skills.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://acacheung.com&quot;&gt;Please take a moment to check out her portfolio&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>BostonRB Goes Live</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/06/11/bostonrb-goes-live" />
    <id>https://dockyard.com/blog/ruby/2012/06/11/bostonrb-goes-live</id>
    <category term="community" label="Community"/><category term="ruby" label="Ruby"/>
    <published>2012-06-11 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Live streaming and expansion comes to BostonRB</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/raigWYs.png&quot; alt=&quot;BostonRB&quot;&gt;&lt;/p&gt;

&lt;p&gt;Starting tomorrow night (June 12th, 2012) &lt;a href=&quot;http://bostonrb.org&quot;&gt;The Boston Ruby Group&lt;/a&gt;
will be streaming its monthly meeting live via &lt;a href=&quot;http://googleblog.blogspot.com/2012/05/google-hangouts-on-air-broadcast-your.html&quot;&gt;Google Hangouts on Air&lt;/a&gt;
The streaming will start at 6:45 PM US Eastern Time and the meeting itself will start at 7pm or a few minutes after. The meeting should run until 9pm.&lt;/p&gt;

&lt;p&gt;This will allow those that cannot attend the meeting to watch the raw
stream live from anywhere in the world on &lt;a href=&quot;http://youtube.com&quot;&gt;YouTube&lt;/a&gt;.
We will also reserve a few seats in the Google Hangout itself for other
user groups in the New England area to join. Questions will be allowed from
these user groups after each presentation just as any
audience member will be able to.&lt;/p&gt;

&lt;p&gt;We&amp;#39;re very excited about using this technology to expand
&lt;a href=&quot;http://bostonrb.org&quot;&gt;BostonRB&lt;/a&gt;. If things go well we will want to
invite more user groups to virtually attend our meetings in the future.
If you are an organizer of a small local group and have difficulty
pulling in some of the larger names in the Ruby community for
presentations we want you to leverage BostonRB.&lt;/p&gt;

&lt;p&gt;In addition, even though Boston is a great tech-hub we still are far
enough away where it is difficult for some presenters to travel. We
would like to invite presenters to BostonRB to present their material
via Google Hangouts.&lt;/p&gt;

&lt;p&gt;In the coming months we plan on using the Google Hangouts technology in
new ways to reach out to our community. Imagine having live office hours
where local expert Ruby devs can answer questions. Or online classes
where students can follow along. We understand that getting to some of our
events can be difficult or even intimidating. Now we can eliminate that
barrier.&lt;/p&gt;

&lt;p&gt;So please follow the &lt;a href=&quot;http://twitter.com/BostonRB&quot;&gt;BostonRB Twitter Account&lt;/a&gt;. Tomorrow night
we&amp;#39;ll tweet the link to the live stream. We&amp;#39;ll also embed the YouTube player
onto the BostonRB homepage. In the future we&amp;#39;ll be making other very
cool announcements as well.&lt;/p&gt;

&lt;p&gt;As always, if you are in Boston we &lt;a href=&quot;http://guestlistapp.com/events/107814&quot;&gt;invite you come to the meeting&lt;/a&gt;
and if you are not in Boston or cannot make it you now have a new
option.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Chris Gill is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2012/06/01/chris-gill-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2012/06/01/chris-gill-is-a-dockyarder</id>
    <category term="announcement" label="Announcement"/><category term="office" label="Office"/>
    <published>2012-06-01 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>DockYard welcomes Chris Gill</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/XxdPnRN.png&quot; alt=&quot;Chris Gill&quot;&gt;&lt;/p&gt;

&lt;p&gt;Today I&amp;#39;m happy to announce that Chris Gill is joining our team!
Chris and I worked together at the &lt;a href=&quot;http://dnc.org&quot;&gt;DNC&lt;/a&gt; and I credit
him with sparking my interest in &lt;a href=&quot;http://www.postgresql.org&quot;&gt;PostgreSQL&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chris&amp;#39; pragmatic approach to software development and his years of
experience in politics is a huge addition to our growing team. He is
located in DC and we hope to soon build out a team in that area.&lt;/p&gt;

&lt;p&gt;Welcome aboard Chris!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/gilltots&quot;&gt;Follow Chris on Twitter&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Rails 4.0 Sneak Peek: Expanded ActiveRecord Support for PostgreSQL Datatypes</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/05/18/rails-4-sneak-peek-expanded-activerecord-support-for-postgresql-datatype" />
    <id>https://dockyard.com/blog/ruby/2012/05/18/rails-4-sneak-peek-expanded-activerecord-support-for-postgresql-datatype</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/><category term="postgresql" label="PostgreSQL"/>
    <published>2012-05-18 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Support added to ActiveRecord for INET, CIDR and MACADDR types for PostgreSQL</summary>
    <content type="html">&lt;p&gt;This week, I had a &lt;a href=&quot;https://github.com/rails/rails/commit/835df6f3ed9b1575fd6a1fb62516d8ebeffbf114#diff-0&quot;&gt;pull request accepted&lt;/a&gt;
into Rails which adds support for
&lt;a href=&quot;http://www.postgresql.org/docs/current/static/datatype-net-types.html&quot;&gt;PostgreSQL&amp;#39;s MACADDR, INET, and CIDR datatypes&lt;/a&gt;.
In Rails 4.0, the following migration will be supported:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;create_table &lt;span class=&quot;symbol&quot;&gt;:network_types&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
  t.cidr &lt;span class=&quot;symbol&quot;&gt;:cidr_address&lt;/span&gt;
  t.inet &lt;span class=&quot;symbol&quot;&gt;:ip_address&lt;/span&gt;
  t.macaddr &lt;span class=&quot;symbol&quot;&gt;:mac_address&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Also, the schema dumper supports these types as well (previously they
would appear as &lt;code&gt;string&lt;/code&gt; types in the schema.rb file).&lt;/p&gt;

&lt;p&gt;ActiveRecord will also cast the values of the INET and CIDR types to
Ruby&amp;#39;s &lt;a href=&quot;http://www.ruby-doc.org/stdlib-1.9.3/libdoc/ipaddr/rdoc/IPAddr.html&quot;&gt;IPAddr&lt;/a&gt;,
while MACADDR will continue to be converted to a string.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Sleep helper for your request tests</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/05/01/simple-sleeper-for-request-testing" />
    <id>https://dockyard.com/blog/ruby/2012/05/01/simple-sleeper-for-request-testing</id>
    <category term="ruby" label="Ruby"/><category term="testing" label="Testing"/>
    <published>2012-05-01 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A clean helper for giving visual feedback on long sleeps in your request tests</summary>
    <content type="html">&lt;p&gt;We have been using &lt;a href=&quot;http://github.com/thoughtbot/capybara-webkit&quot;&gt;capybara-webkit&lt;/a&gt; quite a bit.
Because of the async nature of JavaScript you sometimes have to use
&lt;a href=&quot;http://rubydoc.org/stdlib/core/1.9.2/Kernel#sleep-instance_method&quot;&gt;sleeps&lt;/a&gt; in your tests if the action is taking longer than the default
Capybara 2 second timeout.&lt;/p&gt;

&lt;p&gt;Lately I have had the need to sleep for up to 30
seconds for certain actions and I wanted a clean visual indicator of how
much time was remaining. So I whipped up the following:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;sleep_for&lt;/span&gt;(sleep_time, message = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Sleeping...&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
  sleep_time.times &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |i|
    print_message = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;message&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;sleep_time - i&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; seconds remaining&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    print print_message
    sleep &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
    print [&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\b&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\b&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;].map { |c| c * print_message.length }.join
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I hope others find this useful!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Using Backbone Views With Rails jQuery-ujs</title>
    <link rel="alternate" href="https://dockyard.com/blog/javascript/2012/04/16/using-backbone-views-with-rails-jquery-ujs" />
    <id>https://dockyard.com/blog/javascript/2012/04/16/using-backbone-views-with-rails-jquery-ujs</id>
    <category term="jquery" label="jQuery"/><category term="javascript" label="JavaScript"/><category term="backbone" label="Backbone.js"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2012-04-16 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Russ Jones</name></author>
    <summary>Throwing them together in a way that makes sense.</summary>
    <content type="html">&lt;p&gt;I often meet Rails developers that have unwittingly jumped on the unobtrusive javascript bandwagon. 
They throw &amp;#39;:remote =&amp;gt; true&amp;#39; on a form and benefit from its conventions, but don&amp;#39;t know how to make it really work for them. 
They&amp;#39;re probably still inclined to write out procedural jQuery code the same way they were doing it before &lt;a href=&quot;https://github.com/rails/jquery-ujs&quot;&gt;jquery-ujs&lt;/a&gt; became popular. 
There&amp;#39;s a helpful &lt;a href=&quot;https://github.com/rails/jquery-ujs/wiki/ajax&quot;&gt;wiki page&lt;/a&gt; that describes its custom events and how to use them, but they probably don&amp;#39;t know about it.&lt;/p&gt;

&lt;p&gt;Maybe they&amp;#39;ve worked on improving some client side code with Backbone recently, and maybe they&amp;#39;re trying to do things the Backbone way but don&amp;#39;t know how to tie that together with existing Rails views. 
Here&amp;#39;s a quick example of how Backbone views can listen for jquery-ujs custom events. You can view a working fiddle &lt;a href=&quot;http://jsfiddle.net/codeofficer/mpyXT/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;strong&gt;40&lt;/strong&gt;
41
42
43
44
45
46
47
48
49
&lt;strong&gt;50&lt;/strong&gt;
51
52
53
54
55
56
57
58
59
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;var&lt;/span&gt; FormView = Backbone.View.extend({
  &lt;span class=&quot;key&quot;&gt;el&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#form&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

  &lt;span class=&quot;key&quot;&gt;events&lt;/span&gt;: {
    &lt;span class=&quot;comment&quot;&gt;// Fired automatically when a file-type input is detected with a&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// non-blank value. You can use this hook to implement a handler that&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// will deal with those non-blank file inputs. Returning false will&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// disallow standard form submission.&lt;/span&gt;
    &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajax:aborted:file&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;     : &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajaxAbortedFile&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

    &lt;span class=&quot;comment&quot;&gt;// Fired when there are required inputs which have been left blank.&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// You can use this handler to deal with those blank required inputs.&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// Returning false will submit the form anyway.&lt;/span&gt;
    &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajax:aborted:required&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajaxAbortedRequired&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

    &lt;span class=&quot;comment&quot;&gt;// First event fired for any remote enabled form. Stopping this event&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// will cancel the ajax request&lt;/span&gt;
    &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajax:before&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;           : &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajaxBefore&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

    &lt;span class=&quot;comment&quot;&gt;// Fired before the ajax request is sent. Stopping this event will&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// cancel the ajax request. Commonly used to customize certain request&lt;/span&gt;
    &lt;span class=&quot;comment&quot;&gt;// headers&lt;/span&gt;
    &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajax:beforeSend&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;       : &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajaxBeforeSend&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

    &lt;span class=&quot;comment&quot;&gt;// Fired after completion, if the HTTP response was a success&lt;/span&gt;
    &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajax:success&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;          : &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajaxSuccess&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

    &lt;span class=&quot;comment&quot;&gt;// Fired after completion, if the server returned an error&lt;/span&gt;
    &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajax:error&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;            : &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajaxError&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,

    &lt;span class=&quot;comment&quot;&gt;// Fired after the request has been completed, no matter what outcome&lt;/span&gt;
    &lt;span class=&quot;key&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajax:complete&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;         : &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ajaxComplete&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  },

  &lt;span class=&quot;function&quot;&gt;ajaxAbortedFile&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(e, elements){
  },

  &lt;span class=&quot;function&quot;&gt;ajaxAbortedRequired&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(e, elements){
  },

  &lt;span class=&quot;function&quot;&gt;ajaxBefore&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(e){
  },

  &lt;span class=&quot;function&quot;&gt;ajaxBeforeSend&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(e, xhr, settings){
  },

  &lt;span class=&quot;function&quot;&gt;ajaxSuccess&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(e, data, status, xhr){
  },

  &lt;span class=&quot;function&quot;&gt;ajaxError&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(e, xhr, status, error){
  },

  &lt;span class=&quot;function&quot;&gt;ajaxComplete&lt;/span&gt;: &lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(e, xhr, status){
  }
});

&lt;span class=&quot;predefined&quot;&gt;$&lt;/span&gt;(&lt;span class=&quot;keyword&quot;&gt;function&lt;/span&gt;(){
    window.view = &lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; FormView();
});
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight text &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&amp;lt;form id=&amp;quot;form&amp;quot; action=&amp;quot;#&amp;quot; method=&amp;quot;POST&amp;quot; data-remote=&amp;quot;true&amp;quot;&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;input type=&amp;quot;text&amp;quot; value=&amp;quot;...&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Continue &amp;amp;rarr;&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;</content>
  </entry><entry>
    <title>Tmux, for fun and profit</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/04/10/tmux-for-fun-and-profit" />
    <id>https://dockyard.com/blog/ruby/2012/04/10/tmux-for-fun-and-profit</id>
    <category term="workflow" label="Workflow"/><category term="ruby" label="Ruby"/>
    <published>2012-04-10 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>Pair programming at distance</summary>
    <content type="html">&lt;h2&gt;Screen - the gateway drug&lt;/h2&gt;

&lt;p&gt;I had been using &lt;a href=&quot;http://www.gnu.org/software/screen&quot;&gt;screen&lt;/a&gt; for a while to multiplex my terminal when
working on Ruby projects.  I would have a tab for
&lt;a href=&quot;http://git-scm.org&quot;&gt;git&lt;/a&gt; (was using &lt;a href=&quot;http://code.google.com/p/macvim/&quot;&gt;MacVim&lt;/a&gt;), on for &lt;code&gt;rails s&lt;/code&gt; or &lt;code&gt;tail
log/development.log&lt;/code&gt;, one for running tests (now using &lt;code&gt;guard&lt;/code&gt; or
&lt;code&gt;autotest&lt;/code&gt;), one for &lt;code&gt;rails c&lt;/code&gt; and lastly one for &lt;code&gt;rails db&lt;/code&gt;. Detaching
from a screen session allowed me to have a full environment running
until my next reboot, I could switch back into the project quickly, and
I had configured my &lt;code&gt;.screenrc&lt;/code&gt; to open these tabs everytime I started
screen.&lt;/p&gt;

&lt;p&gt;I also utilized screen to keep sessions open on a remote server between
SSH connects. Instantiating a screen session on the remote server
would keep processes running even when my SSH connection would get
killed. This would prevent an &lt;code&gt;apt-get upgrade&lt;/code&gt; from fragging the system
incase I disconnected, or allow me to drop the connection during a long
running process.&lt;/p&gt;

&lt;p&gt;As much as I used it, I was still a screen newb, as my &lt;code&gt;.screenrc&lt;/code&gt; was
pretty vanilla. I hadn&amp;#39;t taken the time to read the man
pages/tutorials out there to understand some of the more subtle
features.&lt;/p&gt;

&lt;h2&gt;Tmux and Brian P. Hogan&amp;#39;s &amp;#39;tmux&amp;#39; book&lt;/h2&gt;

&lt;p&gt;I had noticed that &lt;a href=&quot;http://tmux.sourceforge.net&quot;&gt;tmux&lt;/a&gt; was getting a decent amount of attention, so
when I started at DockYard, I told myself I would only use tmux.  I also
switched from MacVim to terminal vim, which works better when pair
programming.  &lt;a href=&quot;http://www.bphogan.com&quot;&gt;Brian P. Hogan&lt;/a&gt; recently wrote
&lt;a href=&quot;http://pragprog.com/book/bhtmux/tmux&quot;&gt;tmux: Productive Mouse-Free Development&lt;/a&gt; for Pragmatic Programmers.  After reading his book, I have a solid &lt;code&gt;.tmux.conf&lt;/code&gt; and a great understanding of tmux.&lt;/p&gt;

&lt;h2&gt;Tmux and Pair Programming&lt;/h2&gt;

&lt;p&gt;The one disadvantage of everyone at DockYard working remotely is that you can&amp;#39;t
just turn around and ask someone to come to your desk to pair up. Tmux
allows multiple users to connect to a specific session.  With a bit of
&lt;a href=&quot;http://en.wikipedia.org/wiki/Dynamic_DNS&quot;&gt;dynamic DNS&lt;/a&gt; magic, port forwarding, and ssh tunneling, multiple people
can connect to the same tmux session, work in the same vim window, and
see the same development server.&lt;/p&gt;

&lt;p&gt;The first step is dynamic DNS and port forwarding, which I won&amp;#39;t cover
here, since everyone has different modems and routers. You want to
forward port 22 through your router/firewall to your development
machine. Using dynamic DNS, you can connect to your coworkers via a
domain like &lt;code&gt;dan.example.com&lt;/code&gt; instead of figuring out your IP and
sending that to your partner.&lt;/p&gt;

&lt;p&gt;We use the following ssh command to forward connection on our local
machine to the other person&amp;#39;s&lt;/p&gt;
&lt;div class=&quot;highlight  &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;ssh dan.example.com -L 3000:127.0.0.1:3000
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above command forwards any request on port 3000 on my machine the
one to which I am connected. That way, I can see what my partner sees
when we edit files on his machine.  Once connected, I just attach to my
partner&amp;#39;s tmux session.  At this point, we are programming in the same
terminal session, and we can both see the edits as we make them.  We use
a Google+ Hangout to communicate while we pair program.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;With a tmux, ssh port forwarding, and Google+ Hangout, you can create a
useful pair programming environment with your remote coworkers.  We find
this setup very effective and use it often to work together and tackle
an issue.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Use Association Extensions to Build Join Attributes on a HMT</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/04/03/use-association-extensions-to-build-join-attributes-on-a-hmt" />
    <id>https://dockyard.com/blog/ruby/2012/04/03/use-association-extensions-to-build-join-attributes-on-a-hmt</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/>
    <published>2012-04-03 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Russ Jones</name></author>
    <summary>Russ lays down a use case for ActiveRecord association extensions</summary>
    <content type="html">&lt;p&gt;It&amp;#39;s common in Rails to use a &lt;code&gt;has_many :through&lt;/code&gt; relationship to model User/Group Memberships. 
Sometimes we have extra data in the join that we would like to make use of, but getting that 
data in there can be combersome depending on our approach. For example, given the
following diagram and schema:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/8JgW3es.png&quot; alt=&quot;Diagram&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Schema&lt;/span&gt;.define(&lt;span class=&quot;symbol&quot;&gt;:version&lt;/span&gt; =&amp;gt; &lt;span class=&quot;integer&quot;&gt;20120324170519&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  create_table &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:force&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
    t.string   &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    t.datetime &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:null&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;
    t.datetime &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;updated_at&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:null&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  create_table &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;memberships&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:force&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
    t.integer  &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    t.integer  &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;group_id&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    t.string   &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    t.datetime &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:null&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;
    t.datetime &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;updated_at&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:null&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  create_table &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:force&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |t|
    t.string   &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    t.datetime &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;created_at&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:null&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;
    t.datetime &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;updated_at&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:null&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We might deal directly with the join table to assign our additonal data.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;User 1&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;Group&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Group 1&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
&lt;span class=&quot;instance-variable&quot;&gt;@membership&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;Membership&lt;/span&gt;.create &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |m|
  m.user = &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;
  m.group = &lt;span class=&quot;instance-variable&quot;&gt;@group&lt;/span&gt;
  m.role = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.admin? &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.editor? &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; false&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There&amp;#39;s a better way to pull this off ...&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;instance-variable&quot;&gt;@group&lt;/span&gt;.admins &amp;lt;&amp;lt; &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;
&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.admin? &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.editor? &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; false&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And this is how it&amp;#39;s done ...&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;User&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  has_many &lt;span class=&quot;symbol&quot;&gt;:memberships&lt;/span&gt;
  has_many &lt;span class=&quot;symbol&quot;&gt;:groups&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:through&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:memberships&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;admin?&lt;/span&gt;
    memberships.where(&lt;span class=&quot;symbol&quot;&gt;:role&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).first
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;editor?&lt;/span&gt;
    memberships.where(&lt;span class=&quot;symbol&quot;&gt;:role&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).first
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Membership&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  belongs_to &lt;span class=&quot;symbol&quot;&gt;:group&lt;/span&gt;
  belongs_to &lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Group&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;
  has_many &lt;span class=&quot;symbol&quot;&gt;:memberships&lt;/span&gt;
  has_many &lt;span class=&quot;symbol&quot;&gt;:users&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:through&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:memberships&lt;/span&gt;

  has_many &lt;span class=&quot;symbol&quot;&gt;:admins&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:through&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:memberships&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:source&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt;,
    &lt;span class=&quot;symbol&quot;&gt;:conditions&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;memberships.role = &#39;admin&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;(admin)
        proxy_association.owner.memberships.create(&lt;span class=&quot;symbol&quot;&gt;:role&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt; =&amp;gt; admin)
      &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  has_many &lt;span class=&quot;symbol&quot;&gt;:editors&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:through&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:memberships&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:source&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt;,
    &lt;span class=&quot;symbol&quot;&gt;:conditions&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;memberships.role = &#39;editor&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;(editor)
        proxy_association.owner.memberships.create(&lt;span class=&quot;symbol&quot;&gt;:role&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt; =&amp;gt; editor)
      &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We&amp;#39;re defining an extension on our group&amp;#39;s &lt;code&gt;has_many&lt;/code&gt; association which overrides
the &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; method on that collection. We then tell the proxy association&amp;#39;s owner
(which is our group object) to create the user/group join record, but with an additional
role assignment of &amp;#39;admin&amp;#39;.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;instance-variable&quot;&gt;@group&lt;/span&gt;.admins &amp;lt;&amp;lt; &lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;
&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.admin? &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class=&quot;instance-variable&quot;&gt;@user&lt;/span&gt;.editor? &lt;span class=&quot;comment&quot;&gt;# =&amp;gt; false&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Pretty expressive, thanks to ActiveRecord!&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test_helper&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;GroupTest&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;ActiveSupport&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;TestCase&lt;/span&gt;
  setup &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@user_1&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;User 1&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    &lt;span class=&quot;instance-variable&quot;&gt;@user_2&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;User 2&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    &lt;span class=&quot;instance-variable&quot;&gt;@user_3&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;User 3&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
    &lt;span class=&quot;instance-variable&quot;&gt;@group&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;Group&lt;/span&gt;.create(&lt;span class=&quot;key&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Group 1&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  test &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;No Memberships&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    assert_equal &lt;span class=&quot;instance-variable&quot;&gt;@user_1&lt;/span&gt;.memberships.count, &lt;span class=&quot;integer&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  test &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;@group.users &amp;lt;&amp;lt; @user_1 sets nil role on membership&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@group&lt;/span&gt;.users &amp;lt;&amp;lt; &lt;span class=&quot;instance-variable&quot;&gt;@user_1&lt;/span&gt;
    assert_equal &lt;span class=&quot;instance-variable&quot;&gt;@user_1&lt;/span&gt;.memberships.count, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
    assert_equal &lt;span class=&quot;instance-variable&quot;&gt;@user_1&lt;/span&gt;.memberships.first.role, &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  test &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;@group.admins &amp;lt;&amp;lt; @user_2 sets &#39;admin&#39; role on membership&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@group&lt;/span&gt;.admins &amp;lt;&amp;lt; &lt;span class=&quot;instance-variable&quot;&gt;@user_2&lt;/span&gt;
    assert_equal &lt;span class=&quot;instance-variable&quot;&gt;@user_2&lt;/span&gt;.memberships.count, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
    assert_equal &lt;span class=&quot;instance-variable&quot;&gt;@user_2&lt;/span&gt;.memberships.first.role, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  test &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;@group.editors &amp;lt;&amp;lt; @user_3 sets &#39;editor&#39; role on membership&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@group&lt;/span&gt;.editors &amp;lt;&amp;lt; &lt;span class=&quot;instance-variable&quot;&gt;@user_3&lt;/span&gt;
    assert_equal &lt;span class=&quot;instance-variable&quot;&gt;@user_3&lt;/span&gt;.memberships.count, &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;
    assert_equal &lt;span class=&quot;instance-variable&quot;&gt;@user_3&lt;/span&gt;.memberships.first.role, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;editor&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  teardown &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;constant&quot;&gt;User&lt;/span&gt;.delete_all
    &lt;span class=&quot;constant&quot;&gt;Group&lt;/span&gt;.delete_all
    &lt;span class=&quot;constant&quot;&gt;Membership&lt;/span&gt;.delete_all
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;</content>
  </entry><entry>
    <title>Our Continuous Integration Setup</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/03/05/our-ci-setup" />
    <id>https://dockyard.com/blog/ruby/2012/03/05/our-ci-setup</id>
    <category term="ruby" label="Ruby"/><category term="testing" label="Testing"/><category term="linux" label="Linux"/>
    <published>2012-03-05 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Dan McClain</name></author>
    <summary>What we are doing to keep our developers honest with their tests</summary>
    <content type="html">&lt;p&gt;When I started at DockYard, Brian tasked me with setting up a continous
integration (CI) server so that we could keep an eye on our RSpec test
suite. We went with Jenkins since we are writing client code, so
&lt;a href=&quot;http://travis-ci.org&quot;&gt;travis-ci.org&lt;/a&gt; is out of the question (for now).&lt;/p&gt;

&lt;p&gt;Our CI server is running on Ubuntu 10.04. We are using nginx as a
reverse proxy infront of our Jenkins server. Our basic setup is the same
as &lt;a href=&quot;http://bostonrb.org/presentations/jenkins-rails&quot;&gt;the presentation I gave at Boston RB in January&lt;/a&gt;.
There are a few upgrades I have made since then.  First, I set up the
GitHub authentication plugin. The other plugin I installed was the
Campfire notification plugin. Since we are all remote, we use Campfire
as our main line of communication. Having Jenkins notify us in Campfire
allows us to see when new code is pushed to master, and when someone
breaks the build.&lt;/p&gt;

&lt;h2&gt;RSpec HTML formatter + Jenkins = Every Build is successful (even when it isn&amp;#39;t)&lt;/h2&gt;

&lt;p&gt;As we found out the hard way, using the RSpec HTML formatter from within
jenkins is not the best idea.  The problem is the HTML formatter returns
the same exit code regardless of whether or not the suite passes. This
is a huge problem, as you end up with false positives.&lt;/p&gt;

&lt;h2&gt;Enter ci_reporter&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/nicksieger/ci_reporter&quot;&gt;ci_reporter&lt;/a&gt; gem provides a rake
task that generates a set of xml reports that Jenkins can interpret and
give us a more complete picture of our test suite. Jenkins will plot the
number of failure over time, display test duration, and provide a number 
of other stats you can utilize. &lt;/p&gt;

&lt;h2&gt;Capybara-webkit + Xvfb + headless = Javascript without opening a browser&lt;/h2&gt;

&lt;p&gt;We are using capybara to run our &lt;a href=&quot;http://railscasts.com/episodes/257-request-specs-and-capybara&quot;&gt;request
specs&lt;/a&gt;.
When our request spec needs javascript, we use 
&lt;a href=&quot;https://github.com/thoughtbot/capybara-webkit&quot;&gt;Capybara-webkit&lt;/a&gt; as our
javascript driver. Capybara-webkit is a
webkit capybara driver, allowing you to run javascript in a headless
webkit instance.  It accomplishes this by using QtWebKit. On Ubuntu, to
utilize capybara-webkit, you need an X Server running when you run your
test.  To accomplish this, I installed Xvfb, which will create a
virtual framebuffer.  To instantiate xvfb, I used the headless
gem, which is a ruby wrapper for xvfb.  With headless, I don&amp;#39;t have to
do any bash scripting to get a framebuffer ready before we run our
tests. &lt;/p&gt;

&lt;p&gt;I added the following code to our &lt;code&gt;spec_helper.rb&lt;/code&gt; file&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;config.before(&lt;span class=&quot;symbol&quot;&gt;:suite&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;instance-variable&quot;&gt;@headless&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;Headless&lt;/span&gt;.new
  &lt;span class=&quot;instance-variable&quot;&gt;@headless&lt;/span&gt;.start
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

config.after(&lt;span class=&quot;symbol&quot;&gt;:suite&lt;/span&gt;) &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;instance-variable&quot;&gt;@headless&lt;/span&gt;.destroy
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The above spippet creates the headless instance and creates the
framebuffer at the beginning of the test suite, and destorys it
afterwards.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Overall, I&amp;#39;m pretty happy with our set up as it is. The one issue I have
with it is the way ci_reporter and jenkins interact. Since Jenkins was
origianlly built for Java, builds are BROKEN when they don&amp;#39;t build, but
UNSTABLE when their tests fail.  UNSTABLE builds are seen as successful.
I would rather an UNSTABLE build be seen as a failure, since the
campfire notification plugin plays the same sound for successful and
unstable builds.  I may poke around with the plugin or ci_reporter to
have jenkins notify us of builds in a way that makes more sense.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Dan McClain is a DockYarder</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2012/02/27/dan-mcclain-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2012/02/27/dan-mcclain-is-a-dockyarder</id>
    <category term="office" label="Office"/><category term="announcement" label="Announcement"/>
    <published>2012-02-27 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>DockYard welcomes Dan McClain</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/641zQv4.png&quot; alt=&quot;Dan McClain&quot;&gt;&lt;/p&gt;

&lt;p&gt;Today I&amp;#39;m happy to announce that Dan McClain is joining our team! I&amp;#39;ve
gotten to know Dan over the past few months through
&lt;a href=&quot;http://bostonrb.org&quot;&gt;BostonRB&lt;/a&gt;. He&amp;#39;s been &lt;a href=&quot;https://github.com/bostonrb/bostonrb/commits/master?author=danmcclain&quot;&gt;building out some features for
the BostonRB site&lt;/a&gt;, specifically adding
the start of an admin interface (which is huge for me as I was doing all
data entry through the Rails console) and setting BostonRB up on
&lt;a href=&quot;http://travis-ci.org/#!/bostonrb/bostonrb&quot;&gt;TravisCI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the past few weeks Dan has been working as a contract-to-hire for
us. Already he&amp;#39;s made a big impact by setting up a company instance
of Jenkins and keeping us honest with our test suites.&lt;/p&gt;

&lt;p&gt;Welcome aboard Dan!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/_danmcclain&quot;&gt;Follow Dan on Twitter&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Rails Engines and Monkey Patching</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/02/20/rails-engines-and-monkey-patching" />
    <id>https://dockyard.com/blog/ruby/2012/02/20/rails-engines-and-monkey-patching</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2012-02-20 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A simple pattern for extending your Rails Engines in your app</summary>
    <content type="html">&lt;p&gt;We&amp;#39;ve started extracting simple behavior into Rails Engines lately. An
example of this is our
&lt;a href=&quot;https://github.com/dockyard/invitable&quot;&gt;Invitable&lt;/a&gt; engine. As you may
have guessed, it adds invitation request support to an existing app.
It&amp;#39;s about 50% complete right now but for the purposes of this post it
will act as the example.&lt;/p&gt;

&lt;p&gt;As an engine it has a very slim &lt;code&gt;Invitation&lt;/code&gt; model that only
expects an &lt;code&gt;email&lt;/code&gt; attribute. A client app we&amp;#39;re currently
building requires two additional attributes to be gathered: &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;zipcode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is no need to overwrite the model, I just want to extend it. The cleanest 
thing to do is just monkey patch it.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s start with writing the spec of where I want the model to be (I am
using &lt;a href=&quot;https://github.com/bcardarella/valid_attribute&quot;&gt;ValidAttribute&lt;/a&gt; if
the specs don&amp;#39;t look familiar, I suggest you try it test spec your
validations)&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;spec_helper&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

describe &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Invitation&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  it { should     have_valid(&lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Henry Ford&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
  it { should_not have_valid(&lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;).when(&lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
  it { should     have_valid(&lt;span class=&quot;symbol&quot;&gt;:zipcode&lt;/span&gt;).when(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;02115&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
  it { should_not have_valid(&lt;span class=&quot;symbol&quot;&gt;:zipcode&lt;/span&gt;).when(&lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;0211&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;021156&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To make this spec green there are two things that I have to do&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;zipcode&lt;/code&gt; columsn to the correct table&lt;/li&gt;
&lt;li&gt;Open up the class and add the proper validations on those attributes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first is simple. I just create a new migration and add the columns
to &lt;code&gt;invitable_invitations&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second is not so straight forward. If I open up the class in the client app and
attempt to add the validations like so:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Invitable&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Invitation&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:zipcode&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:presence&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:zipcode&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:format&lt;/span&gt; =&amp;gt; &lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{5}$|^&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{5}-&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{4}$&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The app will raise a &lt;code&gt;NoMethodError&lt;/code&gt; exception complaining that
&lt;code&gt;validates&lt;/code&gt; is undefined. In the load path there are two
&lt;code&gt;app/models/invitable/invitation.rb&lt;/code&gt; files and the one in the app takes precendence
over the one in the engine. This is fine because you might want to
overwrite the model entirely, but in this case I want to extend it. So
you must explicitly require the engine&amp;#39;s model at the top of the app&amp;#39;s model.&lt;/p&gt;

&lt;p&gt;Thankfully the engine itself has a nice helper &lt;code&gt;called_from&lt;/code&gt; that tracks its full path
on the file system. In this example we access it with
&lt;code&gt;Invitable::Engine.called_from&lt;/code&gt;. This will point to the &lt;code&gt;lib/invitable&lt;/code&gt; directory
in the gem itself. Here is what I ended up with in the model:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;constant&quot;&gt;File&lt;/span&gt;.expand_path(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../../app/models/invitable/invitation&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt;.called_from)

&lt;span class=&quot;keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Invitable&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Invitation&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:zipcode&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:presence&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:zipcode&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:format&lt;/span&gt; =&amp;gt; &lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{5}$|^&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{5}-&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{4}$&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It&amp;#39;s verbose and this could be better so let&amp;#39;s clean that up.&lt;/p&gt;

&lt;p&gt;In my engine I&amp;#39;ve added a spec to &lt;code&gt;spec/lib/invitable/engine_spec.rb&lt;/code&gt;
with the following (I&amp;#39;m using &lt;a href=&quot;https://github.com/floehopper/mocha&quot;&gt;Mocha&lt;/a&gt; for the stubbing)&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;spec_helper&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

describe &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  before { &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt;.stubs(&lt;span class=&quot;symbol&quot;&gt;:called_from&lt;/span&gt;).returns(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/lib/invitable&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }

  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.app_path&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns the path to the engine app directory&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt;.app_path.should eq &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller_path&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns the path to the named engine controller&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt;.controller_path(&lt;span class=&quot;symbol&quot;&gt;:test_controller&lt;/span&gt;).should eq &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/app/controllers/invitable/test_controller.rb&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;helper_path&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns the path to the named engine helper&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt;.helper_path(&lt;span class=&quot;symbol&quot;&gt;:test_helper&lt;/span&gt;).should eq &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/app/helpers/invitable/test_helper.rb&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;mailer_path&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns the path to the named engine mailer&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt;.mailer_path(&lt;span class=&quot;symbol&quot;&gt;:test_mailer&lt;/span&gt;).should eq &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/app/mailers/invitable/test_mailer.rb&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;model_path&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns the path to the named engine model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt;.model_path(&lt;span class=&quot;symbol&quot;&gt;:test_model&lt;/span&gt;).should eq &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/app/models/invitable/test_model.rb&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This looks good enough to me. Now to make it green I added the following
to &lt;code&gt;lib/invitable/engine.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;predefined-constant&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;function&quot;&gt;app_path&lt;/span&gt;
  &lt;span class=&quot;constant&quot;&gt;File&lt;/span&gt;.expand_path(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../../app&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, called_from)
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;%w{&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;controller helper mailer model&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.each &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt; |resource|
  class_eval &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;lt;&amp;lt;-RUBY&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;
    def self.&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;resource&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;_path(name)
      File.expand_path(&amp;quot;&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;resource.pluralize&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/invitable/&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\#&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{name}.rb&amp;quot;, app_path)
    end&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;
  RUBY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And now in the app model I can do the following&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;constant&quot;&gt;Inivitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Engine&lt;/span&gt;.model_path &lt;span class=&quot;symbol&quot;&gt;:invitation&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Invitable&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Invitation&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:name&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:zipcode&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:presence&lt;/span&gt; =&amp;gt; &lt;span class=&quot;predefined-constant&quot;&gt;true&lt;/span&gt;
    validates &lt;span class=&quot;symbol&quot;&gt;:zipcode&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:format&lt;/span&gt; =&amp;gt; &lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{5}$|^&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{5}-&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;{4}$&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Nice and clean!&lt;/p&gt;

&lt;p&gt;This simple pattern can be applied to the controllers, mailers, etc... any class you want to actually
extend from the engine instead of overwrite entirely.&lt;/p&gt;

&lt;p&gt;Finally, I&amp;#39;d like the address a question I&amp;#39;m sure some of you have. Why
not subclass? For this engine the &lt;code&gt;Invitable::InvitationsController&lt;/code&gt; is
expecting a class of &lt;code&gt;Invitation&lt;/code&gt; within the context of the &lt;code&gt;Invitable&lt;/code&gt;
module. So if I were to subclass&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Inivtation&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Inivitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;Invitation&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You would then have to subclass the controller&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;InvitationsController&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;InvitationsController&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And because the &lt;code&gt;InvitationsController&lt;/code&gt; is referencing
&lt;code&gt;InvitationMailer&lt;/code&gt; within the context of the &lt;code&gt;Invitable&lt;/code&gt; module you
would have to subclass the mailer&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;InvitationMailer&lt;/span&gt; &amp;lt; &lt;span class=&quot;constant&quot;&gt;Invitable&lt;/span&gt;::&lt;span class=&quot;constant&quot;&gt;InvitationMailer&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Finally, because you&amp;#39;ve subclassed the controller the mount in
&lt;code&gt;routes.rb&lt;/code&gt; becomes meaningless. If you head down the subclass path you
defeat the purpose of using the engine in the first place.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Single quotes or double quotes?</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/02/16/single-quotes-or-double-quotes" />
    <id>https://dockyard.com/blog/ruby/2012/02/16/single-quotes-or-double-quotes</id>
    <category term="ruby" label="Ruby"/><category term="code-guidelines" label="Code Guidelines"/>
    <published>2012-02-16 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>An opinion on when to use the different quoting styles with some performance notes</summary>
    <content type="html">&lt;p&gt;I have a simple rule when it comes to strings: I always start out with
single quotes&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Hello world!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When I need to interpolate in the string or add an escaped character it
is time to upgrade to double quotes&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;planet&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;To: John Adamsn&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;From: Thomas Jefferson&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now what happens when the string style is part of that string itself?
For example, I don&amp;#39;t need to interpolate and the only escaped character
needed is a single quote. This is when I&amp;#39;ve been using &lt;a href=&quot;http://web.njit.edu/all_topics/Prog_Lang_Docs/html/ruby/syntax.html#string&quot;&gt;string
expressions&lt;/a&gt;.
A string literal of &lt;code&gt;%q&lt;/code&gt; is the equivalent of a single quote string and
a &lt;code&gt;%Q&lt;/code&gt; is the equivalent of a double quote string. The string literals
are contained withing a non-alphanumeric delimiter.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# single quote&lt;/span&gt;
&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;%q{&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Wayne&#39;s world!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;# double quote&lt;/span&gt;
&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;%Q{&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;name&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;&#39;s world!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;# ZOMG also a double quote!&lt;/span&gt;
&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;%{&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;name&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;&#39;s world!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I try to follow this rule. I don&amp;#39;t think it saves anything other than it
just looks nicer to me. A very simple (and completely unscientific)
benchmark shows that the difference between the two is a wash&lt;/p&gt;

&lt;p&gt;** Update: These benchmarks may be wrong, please see the comments for more information **&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;benchmark&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;constant&quot;&gt;Benchmark&lt;/span&gt;.measure { &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;integer&quot;&gt;10_000_000&lt;/span&gt;.times { a = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hey now&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; } }
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt;   1.960000   0.000000   1.970000 (  1.958126)&lt;/span&gt;

&lt;span class=&quot;constant&quot;&gt;Benchmark&lt;/span&gt;.measure { &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;integer&quot;&gt;10_000_000&lt;/span&gt;.times { a = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hey now&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } }
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt;   1.980000   0.010000   1.980000 (  1.988363)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Any given run of this and the times would flip. The string is probably
just being optimized somewhere so this benchmark is not very good. At the 
very least it shows that execution time is similar. Let&amp;#39;s see what happens 
when interpolating:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Benchmark&lt;/span&gt;.measure { &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;integer&quot;&gt;10_000_000&lt;/span&gt;.times { |i| a = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hey now &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;i&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; } }
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt;   6.110000   0.010000   6.120000 (  6.111669)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we can see a significant jump in time. (over 3 times longer) Why does this take so much longer?
A clue as to what is happening can be seen when we compare this benchmark to string concatenation using single quotes&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;constant&quot;&gt;Benchmark&lt;/span&gt;.measure { &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;integer&quot;&gt;10_000_000&lt;/span&gt;.times { |i| a = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hey now &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; + i.to_s } }
&lt;span class=&quot;comment&quot;&gt;# =&amp;gt;   6.490000   0.020000   6.510000 (  6.502408)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This ends up being about the same execution time as string interpolation.
Before we answer the previous question let&amp;#39;s take a look at one more option&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;benchmark&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;constant&quot;&gt;Benchmark&lt;/span&gt;.measure { &lt;span class=&quot;integer&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;integer&quot;&gt;10_000_000&lt;/span&gt;.times { |i| a = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;hey now &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &amp;lt;&amp;lt; i } }
&lt;span class=&quot;comment&quot;&gt;#  =&amp;gt;   2.990000   0.010000   3.000000 (  2.986346)&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Whoa, this is much faster, more than 50% faster than interpolation and
concatenation. Why? What is happening here?&lt;/p&gt;

&lt;p&gt;What we are seeing is the difference between creating a new object and
modifying an existing object. It is not immediately obvious with string
interpolation as it is with concatenation. With the append we are actually 
modyfing the object so there is no need to do any memory allocation.&lt;/p&gt;

&lt;p&gt;There are several differences between the two styles, they aren&amp;#39;t
always interchangable. Most of the time the decision comes down to a
styling preference but there are certain use cases where it can make a
difference. String interpolation is in Ruby as a nice convenience but if
you&amp;#39;re doing anything that is relying upon interpolation quite heavily
you may want to consider other options.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Get those instance variables out of my specs!</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/02/15/get-those-instance-variables-out-of-my-specs" />
    <id>https://dockyard.com/blog/ruby/2012/02/15/get-those-instance-variables-out-of-my-specs</id>
    <category term="ruby" label="Ruby"/><category term="testing" label="Testing"/>
    <published>2012-02-15 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Clean up your specs with let and subject</summary>
    <content type="html">&lt;p&gt;If you&amp;#39;ve been writing &lt;a href=&quot;https://www.relishapp.com/rspec&quot;&gt;RSpec&lt;/a&gt; for any
period of time I&amp;#39;m sure you&amp;#39;ve come across &lt;a href=&quot;https://www.relishapp.com/rspec/rspec-core/v/2-8/docs/helper-methods/let-and-let&quot;&gt;let&lt;/a&gt; and &lt;a href=&quot;https://www.relishapp.com/rspec/rspec-core/v/2-8/docs/subject/explicit-subject&quot;&gt;subject&lt;/a&gt;. (please take a moment to check out the links if you have no idea what I&amp;#39;m talking about) In most cases you can write the same specs with instance variables. For example:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.find_good_cars&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  before &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@car_1&lt;/span&gt; = Factory(&lt;span class=&quot;symbol&quot;&gt;:good_car&lt;/span&gt;)
    &lt;span class=&quot;instance-variable&quot;&gt;@car_2&lt;/span&gt; = Factory(&lt;span class=&quot;symbol&quot;&gt;:good_car&lt;/span&gt;)
    &lt;span class=&quot;instance-variable&quot;&gt;@car_3&lt;/span&gt; = Factory(&lt;span class=&quot;symbol&quot;&gt;:bad_car&lt;/span&gt;)
    &lt;span class=&quot;instance-variable&quot;&gt;@good_cars&lt;/span&gt; = &lt;span class=&quot;constant&quot;&gt;Car&lt;/span&gt;.find_good_cars
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;only finds good cars&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;instance-variable&quot;&gt;@good_cars&lt;/span&gt;.should eq [&lt;span class=&quot;instance-variable&quot;&gt;@car_1&lt;/span&gt;, &lt;span class=&quot;instance-variable&quot;&gt;@car_2&lt;/span&gt;]
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here is what it looks like when using &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;subject&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;.find_good_cars&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  let!(&lt;span class=&quot;symbol&quot;&gt;:car_1&lt;/span&gt;) { Factory(&lt;span class=&quot;symbol&quot;&gt;:good_car&lt;/span&gt;) }
  let!(&lt;span class=&quot;symbol&quot;&gt;:car_2&lt;/span&gt;) { Factory(&lt;span class=&quot;symbol&quot;&gt;:good_car&lt;/span&gt;) }
  let!(&lt;span class=&quot;symbol&quot;&gt;:car_3&lt;/span&gt;) { Factory(&lt;span class=&quot;symbol&quot;&gt;:bad_car&lt;/span&gt;)  }
  subject      { &lt;span class=&quot;constant&quot;&gt;Car&lt;/span&gt; }
  its(&lt;span class=&quot;symbol&quot;&gt;:find_good_cars&lt;/span&gt;) { should eq [car_1, car_2] }
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Maybe it is just me but this &lt;em&gt;feels&lt;/em&gt; cleaner. I treat instance
variables in my specs as a smell and you should too.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Love Your lib Directory</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/02/14/love-your-lib-directory" />
    <id>https://dockyard.com/blog/ruby/2012/02/14/love-your-lib-directory</id>
    <category term="ruby" label="Ruby"/><category term="ruby-on-rails" label="Ruby on Rails"/>
    <published>2012-02-14 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Patterns for happy hacking</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;http://blog.codeclimate.com/blog/2012/02/07/what-code-goes-in-the-lib-directory&quot;&gt;Be sure to check out Bryan Helmkamp&amp;#39;s blog post on the same topic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;lib/&lt;/code&gt; directory is the Red Headed Stepchild of your Rails
application. Let&amp;#39;s discuss some conventions for keeping it clean and
what should and shouldn&amp;#39;t go in there.&lt;/p&gt;

&lt;h2&gt;It&amp;#39;s not a dump&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/aEAcAz4.jpg&quot; alt=&quot;Dump&quot;&gt;&lt;/p&gt;

&lt;p&gt;Does this look familiar? It does to me. This is what my &lt;code&gt;lib/&lt;/code&gt; directory
looked like before I got fed up with it. That truck, that was me dumping more
code into &lt;code&gt;lib/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my experience there is one outstanding reason why code ends up
getting dumped into the lib/ directory: A poor understanding of what a
model is. Rails has this way of reinforcing bad habits. Perhaps because
it is so easy to get going some developers never bother to learn that a
model does not in any way need to be attached to a persitence layer.
(i.e. ActiveRecord)&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s all agree to the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;All Business Logic Goes Into A Model&lt;/li&gt;
&lt;li&gt;All Models Go Into &lt;code&gt;app/models&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we say &amp;quot;Business Logic&amp;quot; we are of course talking about &amp;quot;Application
Specific Business Logic&amp;quot;. There is always the case of something you&amp;#39;re
working on that is so generic it can be shared with other applications
you are (or will be) working on. Or, even better, with the community in
general as Open Source. That brings me to the next point.&lt;/p&gt;

&lt;h2&gt;Understanding the load path&lt;/h2&gt;

&lt;p&gt;If you have written a Rubygem, or at the very least, looked through one,
you know that the &lt;code&gt;lib/&lt;/code&gt; directory is special. The short version of the
story is that Rubygems iterates over all of the libraries you have
installed as a gem, and appends any &lt;code&gt;lib/&lt;/code&gt; directories onto Ruby&amp;#39;s Load
Path. This is basically how Ruby gem files are exposed, so when you as
do a gem require it will iterate through every path in the load path and
give you the first match.&lt;/p&gt;

&lt;p&gt;This is also true with Rails. After all of your gems are loaded and your
application is up Rails will append &lt;code&gt;./lib/&lt;/code&gt; to your load path. Any
files you put in there can now be required the exact same way gems are.
This gives us an excellent path to extracting general functionality out
into. You can even play tricks with this, in your &lt;code&gt;application.rb&lt;/code&gt; file
put the following at the top:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;global-variable&quot;&gt;$:&lt;/span&gt;.unshift(&lt;span class=&quot;constant&quot;&gt;File&lt;/span&gt;.expand_path(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;../../lib&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;predefined-constant&quot;&gt;__FILE__&lt;/span&gt;))
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now in your lib directory create an &amp;#39;active_record&amp;#39; directory and add a
file called &amp;#39;base.rb&amp;#39;. Inside that file add the following:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;raise &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;ZOMG I BROKE RAILS!&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Load up your Rails app and watch it throw an exception. Why? Because
your app&amp;#39;s &lt;code&gt;lib/&lt;/code&gt; directory was prepended to the load paths and when the
lookup for &lt;code&gt;active_record/base&lt;/code&gt; happened the first match was in your
app&amp;#39;s &lt;code&gt;lib/&lt;/code&gt; instead of in the proper gem. This of course is more of an interesting hack than anything really
useful. But it does do a good job of demonstrating how Rubygems&amp;#39; lookup
happens.&lt;/p&gt;

&lt;h2&gt;Use initializers for initializing, that is all&lt;/h2&gt;

&lt;p&gt;I have seen developers dump code into initializers that has no business
being there. Yes, it loads and it works. That is not the point. We have
conventions for a reason. Any code that you feel needs to go into an
initializer and has nothing to do with actually setting preferences or
something of that manner almost always should go into the &lt;code&gt;lib/&lt;/code&gt;
directory. If you &lt;strong&gt;must&lt;/strong&gt; monkey patch. Put it into the &lt;code&gt;lib/&lt;/code&gt;
directory. If you are creating a new class or module that has no
business being in &lt;code&gt;app/models&lt;/code&gt; put it in to the &lt;code&gt;lib/&lt;/code&gt; directory.&lt;/p&gt;

&lt;h2&gt;Using lib/ to extend core, stlib, or a gem&lt;/h2&gt;

&lt;p&gt;Far too often I&amp;#39;ve needed to extend a class that is being defined
outside of my project. There are a few ways to deal with this. You can
use a &lt;a href=&quot;http://en.wikipedia.org/wiki/Composite_pattern&quot;&gt;Composite&lt;/a&gt; to
define a new class that you can then play around with. The downside to
this is that I sometimes want to modify a class that is being inherited
by other classes. This is when I think it is appropriate to &lt;a href=&quot;http://en.wikipedia.org/wiki/Monkey_patch&quot;&gt;Monkey
Patch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The pattern I have fallen upon is to define a &lt;code&gt;gem_ext/&lt;/code&gt; directory and a
&lt;code&gt;gem_ext.rb&lt;/code&gt; file in lib. I then make sure the extensions are loaded up
using an initializer. For lack of a better term I call this
&lt;code&gt;lib_loader.rb&lt;/code&gt;. Lets start with the loader.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# config/initializers/lib_loader.rb&lt;/span&gt;

require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;gem_ext&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Simple enough. Now for this example I&amp;#39;ll use a &lt;a href=&quot;http://haml-lang.com/&quot;&gt;Haml&lt;/a&gt; custom filter I wrote.
This filter allows me to write &lt;a href=&quot;http://handlebarsjs.com&quot;&gt;Handlebars&lt;/a&gt;
templates in my views like so:&lt;/p&gt;
&lt;div class=&quot;highlight haml &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;-&lt;span class=&quot;comment&quot;&gt;# app/views/home/show.html.haml&lt;/span&gt;

&lt;span class=&quot;comment&quot;&gt;:handlebars&lt;/span&gt;&lt;span class=&quot;comment&quot;&gt;
  // handlebars code goes here&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now I can easily add handlebar templates to any haml file. This is how I
did it.&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;lib/gem_ext&lt;/code&gt; I defined a &lt;code&gt;haml/&lt;/code&gt; directory and a &lt;code&gt;haml.rb&lt;/code&gt; file. Then I defined &lt;code&gt;haml/custom_filters.rb&lt;/code&gt; and inside that file
I added&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# lib/gem_ext/haml/custom_filters.rb&lt;/span&gt;

&lt;span class=&quot;keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Haml::Filters&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Handlebars&lt;/span&gt;
    include &lt;span class=&quot;constant&quot;&gt;Base&lt;/span&gt;

    &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;render_with_options&lt;/span&gt;(text, options)
      type = &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt; type=&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;options[&lt;span class=&quot;symbol&quot;&gt;:attr_wrapper&lt;/span&gt;]&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;text/x-handlebars&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;options[&lt;span class=&quot;symbol&quot;&gt;:attr_wrapper&lt;/span&gt;]&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;lt;&amp;lt;-END&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;content&quot;&gt;
&amp;lt;script&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;type&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;&amp;gt;
//&amp;lt;![CDATA[
  &lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;text.rstrip.gsub(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;
//]]&amp;gt;
&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;
      END&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now in &lt;code&gt;haml.rb&lt;/code&gt; I added&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# lib/gem_ext/haml.rb&lt;/span&gt;

require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;gem_ext/haml/custom_filters&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And finally in &lt;code&gt;gem_ext.rb&lt;/code&gt; I added&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;comment&quot;&gt;# lib/gem_ext.rb&lt;/span&gt;

require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;gem_ext/haml&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This gives me a very clean approach to extending classes without
worrying about muddying up the load path with name collisions or other
surprises. In addition this pattern can
be repeated for &lt;code&gt;Core&lt;/code&gt; and &lt;code&gt;Stdlib&lt;/code&gt; classes in &lt;code&gt;core_ext&lt;/code&gt; and &lt;code&gt;stdlib_ext&lt;/code&gt;
respectively.&lt;/p&gt;

&lt;h2&gt;Using lib/ as a pattern to extracting Rubygems&lt;/h2&gt;

&lt;p&gt;A pattern I have fallen upon when wanting to extract functionality out
of an app into a Rubygem has been to first extract that code into the
&lt;code&gt;lib/&lt;/code&gt; directoy. From there I have a nice way to test the code in
isolation. I am also forced to write the code as a class independent
from my app. After I am satisfied with what I have I can think about
extracting that into an external gem.&lt;/p&gt;

&lt;p&gt;A great example of this is something that &lt;a href=&quot;http://p-rob.me&quot;&gt;Patrick Robertson&lt;/a&gt; wrote for
&lt;a href=&quot;http://bostonrb.org&quot;&gt;BostonRB&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We wanted to show the next upcoming event at the top of the website. All
of our events are stored in a Google Calendar. Unfortunately most of the
Google Calendar gems out there are crap. Patrick decided to roll his
own.&lt;/p&gt;

&lt;p&gt;You can see that the &lt;a href=&quot;https://github.com/bostonrb/bostonrb/blob/master/lib/boston_rb_calendar.rb&quot;&gt;boston&lt;em&gt;rb&lt;/em&gt;calendar.rb&lt;/a&gt;
is requiring several files just like any Gem would. Because of the
isolation &lt;a href=&quot;https://github.com/bostonrb/bostonrb/blob/master/spec/lib/boston_rb_calendar_spec.rb&quot;&gt;he was able to test the class very easily&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From here, if Patrick wanted to release this as a gem it wouldn&amp;#39;t take
too much effort. Some renaming of classes would be required but he has
all of the major parts in place.&lt;/p&gt;

&lt;h2&gt;Go forth and show some &amp;lt;3&amp;lt;3&amp;lt;3&amp;lt;3&lt;/h2&gt;

&lt;p&gt;Keeping your code clean pays itself forward in many way. The team you
are apart of or the team you are handing off to will thank you. Heck,
your future self might thank you. The patterns I&amp;#39;ve described here are
ones that I have found success with. If you have noticed other patterns
concerning the &lt;code&gt;lib/&lt;/code&gt; directory please feel free to comment!&lt;/p&gt;
</content>
  </entry><entry>
    <title>Authenticating multiple models with a strategy</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/02/13/authenticating-multiple-models-with-a-strategy" />
    <id>https://dockyard.com/blog/ruby/2012/02/13/authenticating-multiple-models-with-a-strategy</id>
    <category term="ruby-on-rails" label="Ruby on Rails"/><category term="design-patterns" label="Design Patterns"/><category term="ruby" label="Ruby"/>
    <published>2012-02-13 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Using the Strategy Pattern to clean up multiple login paths</summary>
    <content type="html">&lt;p&gt;A current project requires that there be multiple models that can sign
in and each one must use the same sign in form. The original
&lt;code&gt;SessionsController#create&lt;/code&gt; action looked like the following:&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;create&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; user = (&lt;span class=&quot;constant&quot;&gt;Owner&lt;/span&gt;.authenticate(params[&lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt;]) || &lt;span class=&quot;constant&quot;&gt;Employee&lt;/span&gt;.authenticate(params[&lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt;]))
    session[&lt;span class=&quot;symbol&quot;&gt;:user_id&lt;/span&gt;]    = user.id
    session[&lt;span class=&quot;symbol&quot;&gt;:user_class&lt;/span&gt;] = user.class
    redirect_to dashboard_path
  &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;
    render &lt;span class=&quot;symbol&quot;&gt;:action&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:new&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We&amp;#39;re using &lt;code&gt;has_secure_password&lt;/code&gt; and rolling our own authentication.
Considering that, the above was good enough. But... looking down
the line for this app it is likely we will have to support authentication
for more than just two models on the same form. I also don&amp;#39;t like having
logic in my controllers. So I decided to break this logic out and I
chose the &lt;a href=&quot;http://en.wikipedia.org/wiki/Strategy_pattern&quot;&gt;Strategy Pattern&lt;/a&gt; to help.&lt;/p&gt;

&lt;p&gt;I like putting all of my strategies into
&lt;code&gt;app/strategies&lt;/code&gt;. This required me to add this directory to the Rails
&lt;code&gt;autoload_paths&lt;/code&gt;. Simply open up &lt;code&gt;config/application.rb&lt;/code&gt;
(not necessary in Rails 3.1+, thanks Artur Roszczyk)&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;config.autoload_paths += &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;%W(&lt;/span&gt;&lt;span class=&quot;inline&quot;&gt;&lt;span class=&quot;inline-delimiter&quot;&gt;#{&lt;/span&gt;config.root&lt;span class=&quot;inline-delimiter&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;/app/strategies&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next I wrote up a simple spec, thankfully I already had the logic from
the controller so there wasn&amp;#39;t much work to be done here. This went into
&lt;code&gt;spec/strategies/authentication_strategy_spec.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;strong&gt;10&lt;/strong&gt;
11
12
13
14
15
16
17
18
19
&lt;strong&gt;20&lt;/strong&gt;
21
22
23
24
25
26
27
28
29
&lt;strong&gt;30&lt;/strong&gt;
31
32
33
34
35
36
37
38
39
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;require &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;spec_helper&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

describe &lt;span class=&quot;constant&quot;&gt;AuthenticationStrategy&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
  context &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;authenticating an owner&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    let(&lt;span class=&quot;symbol&quot;&gt;:owner&lt;/span&gt;) { mock(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Owner&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    before &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      owner.stubs(&lt;span class=&quot;symbol&quot;&gt;:authenticate&lt;/span&gt;).returns(owner)
      &lt;span class=&quot;constant&quot;&gt;Owner&lt;/span&gt;.stubs(&lt;span class=&quot;symbol&quot;&gt;:where&lt;/span&gt;).returns([owner])
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
    it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns an owner&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;constant&quot;&gt;AuthenticationStrategy&lt;/span&gt;.run(&lt;span class=&quot;symbol&quot;&gt;:email&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;owner@example.com&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).should eq owner
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  context &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;authenticating an employee&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    let(&lt;span class=&quot;symbol&quot;&gt;:employee&lt;/span&gt;) { mock(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Employee&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;) }
    before &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      employee.stubs(&lt;span class=&quot;symbol&quot;&gt;:authenticate&lt;/span&gt;).returns(employee)
      &lt;span class=&quot;constant&quot;&gt;Employee&lt;/span&gt;.stubs(&lt;span class=&quot;symbol&quot;&gt;:where&lt;/span&gt;).returns([employee])
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
    it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns an employee&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;constant&quot;&gt;AuthenticationStrategy&lt;/span&gt;.run(&lt;span class=&quot;symbol&quot;&gt;:email&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;employee@example.com&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).should eq employee
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;

  describe &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;failing to authenticate&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
    context &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;with no attributes&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns nil&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;constant&quot;&gt;AuthenticationStrategy&lt;/span&gt;.run.should be_nil
      &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
    context &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;with no match for owner or employee&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
      it &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;returns nil&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;constant&quot;&gt;AuthenticationStrategy&lt;/span&gt;.run(&lt;span class=&quot;symbol&quot;&gt;:email&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;test@example.com&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).should be_nil
      &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now it was time to make these specs green! The strategy file goes into
&lt;code&gt;app/strategies/authentication_strategy.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;AuthenticationStrategy&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;predefined-constant&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;function&quot;&gt;run&lt;/span&gt;(attributes = &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt;)
    &lt;span class=&quot;keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;predefined-constant&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; (attributes.nil? || attributes[&lt;span class=&quot;symbol&quot;&gt;:email&lt;/span&gt;].blank? || attributes[&lt;span class=&quot;symbol&quot;&gt;:password&lt;/span&gt;].blank?)
    &lt;span class=&quot;constant&quot;&gt;Owner&lt;/span&gt;.authenticate(attributes) || &lt;span class=&quot;constant&quot;&gt;Employee&lt;/span&gt;.authenticate(attributes)
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And finally to clean up the controller&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;create&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;if&lt;/span&gt; user = &lt;span class=&quot;constant&quot;&gt;AuthenticationStrategy&lt;/span&gt;.run(params[&lt;span class=&quot;symbol&quot;&gt;:user&lt;/span&gt;])
    session[&lt;span class=&quot;symbol&quot;&gt;:user_id&lt;/span&gt;]    = user.id
    session[&lt;span class=&quot;symbol&quot;&gt;:user_class&lt;/span&gt;] = user.class
    redirect_to dashboard_path
  &lt;span class=&quot;keyword&quot;&gt;else&lt;/span&gt;
   render &lt;span class=&quot;symbol&quot;&gt;:action&lt;/span&gt; =&amp;gt; &lt;span class=&quot;symbol&quot;&gt;:new&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the end this may appear to be more work than is necessary. Keep in
mind that app requirements will expand to support more models. The wins should be obvious
considering that context. If the requirements grow to 5 or 6 models perhaps at that point it makes sense to
actually break the authentication up into &lt;a href=&quot;http://en.wikipedia.org/wiki/Identity_management&quot;&gt;Identities&lt;/a&gt; with a &lt;a href=&quot;http://guides.rubyonrails.org/association_basics.html#polymorphic-associations&quot;&gt;polymorphic
association&lt;/a&gt; to the different models.
But we&amp;#39;ll cross that road when we get there.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Angelo Simeoni is a DockYarder!</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2012/02/10/angelo-simeoni-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2012/02/10/angelo-simeoni-is-a-dockyarder</id>
    <category term="announcement" label="Announcement"/><category term="office" label="Office"/>
    <published>2012-02-10 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>DockYard welcomes Angelo Simeoni as a partner</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/DUKUM7V.png&quot; alt=&quot;Angelo Simeoni&quot;&gt;&lt;/p&gt;

&lt;p&gt;I first met Angelo when we both worked at &lt;a href=&quot;http://zendesk.com&quot;&gt;zendesk&lt;/a&gt; two years ago. I had heard about him before this as he had done some redesigns for &lt;a href=&quot;http://bostonrb.org&quot;&gt;The Boston Ruby Group&lt;/a&gt; website. Over the few months that zendesk was in Boston we got to be friends, and when we both left zendesk I knew this was someone I wanted to work with again in the future. That opportunity came when I moved back to Boston in the summer of 2010. For the past year Angelo and I have been collaborating on several projects and I&amp;#39;m happy to announce that he has agreed to come on as a partner for DockYard.&lt;/p&gt;

&lt;p&gt;Angelo has been working in Rails for a few years now, and is a master of
all things CSS. His love for typefaces has influenced me quite a bit in
how I approach web design.&lt;/p&gt;

&lt;p&gt;You can view a lot of Angelo&amp;#39;s work over at his personal site:
&lt;a href=&quot;http://cssboy.com&quot;&gt;CSSBoy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/cssboy&quot;&gt;Follow Angelo on Twitter&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>Russ Jones is a DockYarder!</title>
    <link rel="alternate" href="https://dockyard.com/blog/announcement/2012/02/10/russ-jones-is-a-dockyarder" />
    <id>https://dockyard.com/blog/announcement/2012/02/10/russ-jones-is-a-dockyarder</id>
    <category term="announcement" label="Announcement"/><category term="office" label="Office"/>
    <published>2012-02-10 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>DockYard welcomes Russ Jones as a partner</summary>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/9AZ94dd.png&quot; alt=&quot;Russ Jones&quot;&gt;&lt;/p&gt;

&lt;p&gt;Russ and I met during the first &lt;a href=&quot;http://railscamps.com&quot;&gt;Rails Camp New
England&lt;/a&gt;. Over the past few years we&amp;#39;ve gotten to know one another and have been looking to collaborate as developers. Last March Russ, myself, and a few others, got together to talk about the possibility of starting our own consultancy. Since getting a bunch of freelancers on the same schedule is difficult, it wasn&amp;#39;t until 8 months later that I was finally able to bring Russ in on a project.&lt;/p&gt;

&lt;p&gt;Russ has been developing in Rails since 2006, but has been focusing most of his recent development efforts on the client. When we joined up he immediately took ownership of a mobile web application, bringing some sanity to a combination of Phonegap, jQueryMobile and Backbone. He&amp;#39;s already released a few open source projects for DockYard: &lt;a href=&quot;https://github.com/dockyard/jquerymobile-backbone&quot;&gt;jquery-backbone&lt;/a&gt; and &lt;a href=&quot;https://github.com/dockyard/ember-jasmine-standalone&quot;&gt;ember-jasmine-standalone&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I&amp;#39;m very happy to announce that Russ has agreed to come on board as a
partner.&lt;/p&gt;

&lt;p&gt;Now I just have to get him to write some blog posts...&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/codeofficer&quot;&gt;Follow Russ on Twitter&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>ClientSideValidations goes modular</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2012/01/22/client-side-validations-goes-modular" />
    <id>https://dockyard.com/blog/ruby/2012/01/22/client-side-validations-goes-modular</id>
    <category term="gems" label="Gems"/><category term="ruby-on-rails" label="Ruby on Rails"/><category term="ruby" label="Ruby"/>
    <published>2012-01-22 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Brian summarizes the changes to come in ClientSideValidations 3.2.0</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/bcardarella/client_side_validations&quot;&gt;ClientSideValidations&lt;/a&gt; has been gaining popularity over the past few
months as it is nearing 1000 watchers on Github. With the release of
Rails 3.2.0 I&amp;#39;ve decided to start extracting out all of the non-Rails
components, such as SimpleForm support and Mongoid support, into their
own gems. I want to disucss my reasons for doing this as I believe this
path of modularity is going to mean better gem maintenance, more frequent
releases, and the opportunity for the community to really get involved.&lt;/p&gt;

&lt;p&gt;Last night I released ClientSideValidations-3.2.0.beta.1 and I have extracted the following into their own gems:&lt;/p&gt;

&lt;h5&gt;ORMs&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/client_side_validations-mongoid&quot;&gt;ClientSideValidations-Mongoid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/client_side_validations-mongo_mapper&quot;&gt;ClientSideValidations-MongoMapper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;FormBuilders&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/client_side_validations-formtastic&quot;&gt;ClientSideValidations-Formtastic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dockyard/client_side_validations-simple_form&quot;&gt;ClientSideValidations-SimpleForm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Going Modular&lt;/h2&gt;

&lt;p&gt;The problem with keeping support for the many different ORMs and
FormBuilders in the ClientSideValidations gem is that there are just too
many dependencies doing different things. A great example is with
Mongoid and &lt;a href=&quot;https://github.com/bcardarella/client_side_validations/issues/253&quot;&gt;ClientSideValidations Issue #253&lt;/a&gt;.
Mongoid &lt;code&gt;2.4.0&lt;/code&gt; added a &lt;a href=&quot;https://github.com/mongoid/mongoid/blob/2.4.0-stable/lib/mongoid/validations/presence.rb&quot;&gt;PresenceValidator&lt;/a&gt; instead of using
the ActiveModel version. This caused translations to fail as they were
being served up directly from Mongoid instead of ActiveModel. I could
have fixed this easily in ClientSideValidations but now this means all
future releases would require anyone using a version of Mongoid previous
to this change to upgrade. There are many reason why you may not want to
upgrade Mongoid, none of which are my business.&lt;/p&gt;

&lt;p&gt;Pulling the Mongoid code out into its own plugin allows this bug to be
fixed there and I can continue to do bug fixes/feature development in
ClientSideValidations that everyone can benefit from.&lt;/p&gt;

&lt;h2&gt;More than just SemVer&lt;/h2&gt;

&lt;p&gt;The versions of the plugins now matter. I&amp;#39;ve decided to
match the library they are supporting&amp;#39;s Major and Minor version. For
example, with Mongoid the current version is &lt;code&gt;2.4.x&lt;/code&gt; so the current
version of &lt;a href=&quot;https://github.com/dockyard/client_side_validations-mongoid&quot;&gt;ClientSideValidations-Mongoid&lt;/a&gt;
is &lt;code&gt;2.4.0&lt;/code&gt;. All bug fixes for this version will only bump the patch
version. We can then go back and add a &lt;code&gt;2.3.0&lt;/code&gt; version that does not
expect a Mongoid PresenceValidator and you won&amp;#39;t need to change the
version of ClientSideValidations. Simple enough stuff, but it gives the
library a lot of flexibility.&lt;/p&gt;

&lt;h2&gt;Community Support&lt;/h2&gt;

&lt;p&gt;I won&amp;#39;t go back and cover every single Major/Minor
release of the different gems. I&amp;#39;m starting with the current versions
and going to look to the community to send pull-requests to fill in the
gaps.&lt;/p&gt;

&lt;p&gt;With these ORM and FormBuilder gems the community should have a good
starting point for writing their own ClientSideValidations plugins.&lt;/p&gt;

&lt;p&gt;If someone is looking for a good starting point to build a gem you can
start with NestedForm as this is a gem that I did not extract and its
support was dropped.&lt;/p&gt;

&lt;p&gt;In addition, I&amp;#39;m looking for help. It would be nice to get some
maintainers on the plugins but I&amp;#39;m also looking for someone to lend a
hand with ClientSideValidations.&lt;/p&gt;

&lt;h2&gt;When will it be released?&lt;/h2&gt;

&lt;p&gt;I&amp;#39;ve got a bunch of &lt;a href=&quot;https://github.com/bcardarella/client_side_validations/issues&quot;&gt;issues in
ClientSideValidations&lt;/a&gt; I want to fix, I&amp;#39;m
guessing maybe a week or two to get through all of these. I&amp;#39;ll go
through a few &lt;code&gt;beta&lt;/code&gt; gems then a release candidate or two. I am always open to community contributions. If you want to help, please do!&lt;/p&gt;

&lt;p&gt;You can start using this today with the beta version. All of the plugins
require the beta version of ClientSideValidations 3.2.0.&lt;/p&gt;

&lt;h2&gt;The Future&lt;/h2&gt;

&lt;p&gt;Rails &lt;code&gt;3.2.0&lt;/code&gt; will be the last &lt;code&gt;3.x&lt;/code&gt; version of Rails, and so this will
also be the last &lt;code&gt;3.x&lt;/code&gt; version of ClientSideValidations. Work is already
underway on the &lt;code&gt;4.x&lt;/code&gt; version. One of the biggest changes is going to
happen on the JavaScript side. Client-side model validations will be the
goal. As well as compostite views for the error rendering. Ideally I
would like ClientSideValidations to be able to hook into the popular
JavaScript MVC frameworks.&lt;/p&gt;
</content>
  </entry><entry>
    <title>It&#39;s Not A Vacation Follow Up</title>
    <link rel="alternate" href="https://dockyard.com/blog/2012/01/04/its-not-a-vacation-follow-up" />
    <id>https://dockyard.com/blog/2012/01/04/its-not-a-vacation-follow-up</id>
    <category term="office" label="Office"/>
    <published>2012-01-04 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;We have been pretty busy here at DockYard and I haven&amp;#39;t had a chance to
follow up on the &lt;a href=&quot;/2011/12/04/its-not-a-vacation.html&quot;&gt;previous post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To recap: DockYard is a distributed team, we decided to switch it up for
a week and go to the same city and work our asses off.&lt;/p&gt;

&lt;p&gt;Result: We kicked ass.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/4oG6ECL.jpg&quot; alt=&quot;Dan Pickett &amp;amp; Russ Jones&quot;&gt;&lt;/p&gt;

&lt;p&gt;The city we chose to work from for the week is Providence, RI. It was
close enough most of the team to not be expensive to travel to yet far
enough away to necessitate not going home each night. On top of that,
Providence is a very affordable city and it has a tech scene that is
starting to take off.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/nBZMrGO.jpg&quot; alt=&quot;Tazza Cafe&quot;&gt;&lt;/p&gt;

&lt;p&gt;For the week we worked from &lt;a href=&quot;http://tazzacaffe.com&quot;&gt;Tazza Cafe&lt;/a&gt; and I
have only the highest praise for the atmosphere, the food, and the
staff. Free wi-fi, never too crowded, amazing food selection, and some
of the friendliest wait staff I&amp;#39;ve ever seen at anywhere. If you in the
area, or just passing through, I highly recommend stopping in.&lt;/p&gt;

&lt;p&gt;The progress we made during the week was pretty amazing. This type of
work is only possible with a great team. We were
fortuante enough to be joined by &lt;a href=&quot;http://enlightsolutions.com&quot;&gt;Dan
Pickett&lt;/a&gt; along with the DockYard regulars
of &lt;a href=&quot;http://cssboy.com&quot;&gt;Angelo Simeoni&lt;/a&gt;, &lt;a href=&quot;http://codeofficer.com&quot;&gt;Russ
Jones&lt;/a&gt;, and myself.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/eGkHJxu.jpg&quot; alt=&quot;Downtown Providence&quot;&gt;&lt;/p&gt;

&lt;p&gt;During the week we got to meet many from the local tech scene. Monday
night we crashed a &lt;a href=&quot;http://betaspring&quot;&gt;Betaspring&lt;/a&gt; event and Thursday we
hosted our own Providence Pub Crawl hitting &lt;a href=&quot;http://as220.org/&quot;&gt;AS220&lt;/a&gt;,
&lt;a href=&quot;http://www.trinitybrewhouse.com&quot;&gt;Trinity Brewhouse&lt;/a&gt;, Union Station
Brewery, &lt;a href=&quot;http://www.trinitybrewhouse.com&quot;&gt;Rira&lt;/a&gt;, and ending up at
Tazza. It was a great way to end a great week. We&amp;#39;ll be doing this again
in the future.&lt;/p&gt;
</content>
  </entry><entry>
    <title>It&#39;s Not A Vacation</title>
    <link rel="alternate" href="https://dockyard.com/blog/2011/12/04/its-not-a-vacation" />
    <id>https://dockyard.com/blog/2011/12/04/its-not-a-vacation</id>
    <category term="office" label="Office"/>
    <published>2011-12-04 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;h3&gt;DockYard is invading The Ocean State!&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/j46sVqU.jpg&quot; alt=&quot;Ocean State&quot;&gt;&lt;/p&gt;

&lt;p&gt;There is one annoying issue working with a remote team:
Everybody is remote. There is something lost when you don&amp;#39;t get to see the people you&amp;#39;re working with.
Apps like Skype have made a difference how remote work is done. We&amp;#39;re
not any less productive, but it&amp;#39;s difficult to grab drinks with co-workers
when they&amp;#39;re 2 hours away.&lt;/p&gt;

&lt;p&gt;To that end we&amp;#39;ve decided to work from a city for a week once every
few months. We&amp;#39;ll pack up, grab a hotel, and lock ourselves in a coffee
shop to get a crazy amount of work done. Our girlfriends and wives
might disagree but we&amp;#39;re calling this: &lt;strong&gt;It&amp;#39;s Not A Vacation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We&amp;#39;re very serious about this, the entire week is a dedicated work week.
We&amp;#39;ve set some ambitious goals for our client applications and we&amp;#39;re
all pretty fired up to get going. There is something interesting that
happens to productivity with you shake things up.&lt;/p&gt;

&lt;p&gt;This is of course all experimental so I&amp;#39;ll write a follow up at the end
of the week on how things went.&lt;/p&gt;
</content>
  </entry><entry>
    <title>Convert Ruby Regexp to JavaScript RegExp</title>
    <link rel="alternate" href="https://dockyard.com/blog/ruby/2011/11/18/convert-ruby-regexp-to-javascript-regex" />
    <id>https://dockyard.com/blog/ruby/2011/11/18/convert-ruby-regexp-to-javascript-regex</id>
    <category term="javascript" label="JavaScript"/><category term="ruby" label="Ruby"/>
    <published>2011-11-18 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>A simple extraction from ClientSideValidations</summary>
    <content type="html">&lt;p&gt;This has a very limited use case, but I needed it for
&lt;a href=&quot;http://github.com/bcardarella/client_side_validations&quot;&gt;ClientSideValidations&lt;/a&gt;. It took a while
to track down some of the possible conversion issues, I figure someone
else might find this useful.&lt;/p&gt;
&lt;div class=&quot;highlight ruby &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
2
3
4
5
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;class&quot;&gt;Regexp&lt;/span&gt;
  &lt;span class=&quot;keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;function&quot;&gt;to_javascript&lt;/span&gt;
    &lt;span class=&quot;constant&quot;&gt;Regexp&lt;/span&gt;.new(inspect.sub(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).sub(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).sub(&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).sub(&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\/&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).sub(&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\/&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;[a-z]*$&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).gsub(&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\?&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;#.+&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;).gsub(&lt;span class=&quot;regexp&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\?&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;char&quot;&gt;\w&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;+:&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;,&lt;span class=&quot;string&quot;&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;content&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;delimiter&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;), &lt;span class=&quot;predefined-constant&quot;&gt;self&lt;/span&gt;.options).inspect
  &lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;keyword&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;When you render it to the client simply instantiate a new &lt;code&gt;RegExp&lt;/code&gt;
object with the resulting string:&lt;/p&gt;
&lt;div class=&quot;highlight javascript &quot;&gt;&lt;div class=&quot;ribbon&quot;&gt;&lt;/div&gt;&lt;div class=&quot;scroller&quot;&gt;&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td class=&quot;line-numbers&quot;&gt;&lt;pre&gt;1
&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;keyword&quot;&gt;new&lt;/span&gt; RegExp(regexpStringFromRuby);
&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If there are any edge-cases that won&amp;#39;t convert cleanly please report
them in the comments.&lt;/p&gt;

&lt;p&gt;See how it is being used in &lt;code&gt;ClientSideValidations&lt;/code&gt; &lt;a href=&quot;https://github.com/bcardarella/client_side_validations/blob/master/lib/client_side_validations/core_ext/regexp.rb&quot;&gt;to_json&lt;/a&gt;
&lt;a href=&quot;https://github.com/bcardarella/client_side_validations/blob/master/test/core_ext/cases/test_core_ext.rb&quot;&gt;tests cases&lt;/a&gt;&lt;/p&gt;
</content>
  </entry><entry>
    <title>GitHub Is One Commit Away From Being The Ultimate Blog Engine</title>
    <link rel="alternate" href="https://dockyard.com/blog/2011/11/14/github-is-one-commit-away-from-being-the-ultimate-blog-engine" />
    <id>https://dockyard.com/blog/2011/11/14/github-is-one-commit-away-from-being-the-ultimate-blog-engine</id>
    <category term="opinion" label="Opinion"/>
    <published>2011-11-14 00:00:00</published>
    <updated>2016-02-01 16:29:39</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;This past August &lt;a href=&quot;https://github.com/blog/905-edit-like-an-ace&quot;&gt;GitHub released file editing using the Ace code
editor&lt;/a&gt;. It&amp;#39;s pretty damn
awesome if you haven&amp;#39;t tried it. Basically, you get
&lt;a href=&quot;http://macromates.com&quot;&gt;TextMate&lt;/a&gt; in your
browser. Here at &lt;a href=&quot;https://dockyard.com&quot;&gt;DockYard&lt;/a&gt; we&amp;#39;ve been using
&lt;a href=&quot;http://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; to host this blog. The posts
are written in &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;. So we&amp;#39;re
doing all of our post creation and editing locally.&lt;/p&gt;

&lt;h2&gt;The Dream&lt;/h2&gt;

&lt;p&gt;It would be great if GitHub allowed us to create new &lt;a href=&quot;http://book.git-scm.com/1_the_git_object_model.html&quot;&gt;blobs&lt;/a&gt; from the web interface.
At that point GitHub would be a full-service blog engine. Think about it, they already do the
hosting, version tracking, and editing of files through the web
interface. If file creation was added that&amp;#39;s pretty much all I would
want. (&lt;a href=&quot;https://github.com/mojombo/jekyll/wiki/YAML-Front-Matter&quot;&gt;Jekyll has a way to track drafts by setting the &lt;code&gt;published&lt;/code&gt;
flag&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So if anybody at GitHub is reading, can we please have this feature?&lt;/p&gt;
</content>
  </entry><entry>
    <title>Mobile Web Apps Still Have Some Major Hurdles</title>
    <link rel="alternate" href="https://dockyard.com/blog/2011/11/10/mobile-web-apps" />
    <id>https://dockyard.com/blog/2011/11/10/mobile-web-apps</id>
    <category term="mobile-web" label="Mobile Web"/><category term="mobile" label="Mobile"/>
    <published>2011-11-10 00:00:00</published>
    <updated>2016-02-01 14:21:03</updated>
    <author><name>Brian Cardarella</name></author>
    <summary>Brian summarizes DockYard&#39;s experience thus far with mobile web apps and some of the existing challenges to compete with native</summary>
    <content type="html">&lt;p&gt;Over the past 24 hours I&amp;#39;ve seen several articles (&lt;a href=&quot;http://venturebeat.com/2011/11/09/mobile-web/&quot;&gt;1&lt;/a&gt;,&lt;a href=&quot;http://www.guardian.co.uk/technology/blog/2011/nov/03/will-html5-replace-native-apps&quot;&gt;2&lt;/a&gt;) on &lt;a href=&quot;http://news.ycombinator.com&quot;&gt;Hacker News&lt;/a&gt;
predicting that in the near future mobile web apps are going to
replace their native counterparts. Here at DockYard we really hope this
happens. We believe in the mobile web and have decided forego regular
web application development in favor of focusing on mobile web
application development. However, experience has told us the future is not as nigh as we
all hope.&lt;/p&gt;

&lt;p&gt;Native applications (iOS, Android, etc.) still have and will continue
to have some significant advantages over mobile web apps. Let&amp;#39;s start
with the obvious...&lt;/p&gt;

&lt;h3&gt;Native functionality&lt;/h3&gt;

&lt;p&gt;Having access to mobile hardware such as the camera, microphone, and
storage (file system, internal datbases, etc...) is important. There is also the issue
of running the application in the background. None of this is currently
possible in a mobile web application. Immediately the scope of a mobile
web application is much smaller.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://www.w3.org/TR/html-media-capture/&quot;&gt;W3C has a working draft of what a media capture API should
be&lt;/a&gt;. It may be a
matter of time until we see mobile browsers begin to provide access to
this native functionality. Personally, I would like to see this API
developed further. In its current form it is simply a delegator API to
the camera and microphone applications. We hand off application control and wait for a
callback that has the list of media just captured. This is not good
enough. How can a mobile web application compete with the many
different native camera applications that exist with custom camera
functionality if there is no way to
customize the camera experience? Simple: it can&amp;#39;t. Augmented reality
mobile web application? Nope. What about something as simple as skinning
the camera? Not with the current working draft of the MediaCapture API.&lt;/p&gt;

&lt;p&gt;Most mobile web browsers implement the HTML canvas element. So mobile
web gaming is possible. But what we really want is hardware accelerated
WebGL. It&amp;#39;s not here yet. We&amp;#39;re still waiting for the desktop
canvas apps to close the gap between their native desktop counterparts.
Mobile web gaming will not be competing with native mobile gaming
anytime soon.&lt;/p&gt;

&lt;h3&gt;Performance&lt;/h3&gt;

&lt;p&gt;Native is the clear winner here but with each new generation of phone
hardware the lead is becoming less noticeable. In fact, I&amp;#39;m going to
predict that in the 2nd half of 2012 (iPhone5, assuming Apple goes back
to the previous iPhone release cycle) for everything
except gaming, the difference will be negligible.&lt;/p&gt;

&lt;p&gt;We&amp;#39;re getting closer and closer to the point of convergence. Hardware is
getting faster, JavaScript VMs are getting faster. Native and mobile web
apps will never be equally as fast, native will &lt;strong&gt;always&lt;/strong&gt; be faster.
With each generation of mobile hardware we will care less because the gap will continue to get asymptotically
smaller.&lt;/p&gt;

&lt;p&gt;This current performance gap can be felt most with &lt;a href=&quot;http://jquerymobile.com&quot;&gt;jQuery
Mobile&lt;/a&gt;. We use jQuery Mobile, we believe in
it. On the latest iPhone 4S there is still a noticeable lag when
doing page trasitions, even on mobile web applications that have very few
pages of low complexity. The page enhancement algorithm does &lt;strong&gt;a lot&lt;/strong&gt; of
DOM manipulation and hoop jumping. Elements are pulled out of the DOM,
wrapped, reinserted. In the end it allows us to
provide very little markup and get some beautiful results.&lt;/p&gt;

&lt;p&gt;As of this writing jQuery Mobile is in 1.0 Release Candidate 2. On the bucket
list for 1.0 Gold is a &lt;a href=&quot;https://github.com/jquery/jquery-mobile/issues/2853&quot;&gt;performance boost for page enhancement&lt;/a&gt;.
&lt;a href=&quot;https://twitter.com/#!/jquerymobile/status/133670336318291969&quot;&gt;Most likely this will only have an effect upon very complex pages&lt;/a&gt;.
Closing the performance gap on jQuery Mobile is going to be a watershed
moment for mobile web application development.&lt;/p&gt;

&lt;h3&gt;Distribution&lt;/h3&gt;

&lt;p&gt;Nothing beats the web as a distribution platform. Every time I use a web
app I am on the latest version of that app. If there are any business
critical updates they are immediately available for everybody. Native
mobile applications are at a clear disadvantage here. We&amp;#39;re comparing a
passive opt-in system to an active apt-in system.&lt;/p&gt;

&lt;p&gt;One disadvantage (for now) that mobile web applications have is
accessibility after distribution. Native apps default to installing on
your phone, mobile web applications do not. Yes, you can save links to
the mobile web app and make it appear you have it installed. But what
about off-line mode?&lt;/p&gt;

&lt;h3&gt;Discovery&lt;/h3&gt;

&lt;p&gt;I&amp;#39;m going to argue that native applications win here. Finding a native
mobile application is easier than finding a mobile web application.
Google has made a large dent for the web with Chrome&amp;#39;s Omnibar. (btw,
why hasn&amp;#39;t everybody copied the omnibar? This should be the default for mobile
web browsers, screen real estate is already at a premium.)&lt;/p&gt;

&lt;p&gt;That being said, discovery for native is not great. We&amp;#39;ve
all see the studies where the Top 10 apps have a significantly skewed
download rate compared to the below Top 10. This is be expected. I don&amp;#39;t
understand why the mobile app stores have not put more effort into
perfecting discovery. I&amp;#39;m more likely to purchase an application that I
like if I can find it easily.&lt;/p&gt;

&lt;h3&gt;PhoneGap (Apache Callback)&lt;/h3&gt;

&lt;p&gt;If you&amp;#39;ve made it this far you&amp;#39;ve probably been yelling at your screen
&amp;quot;&lt;strong&gt;PhoneGap!&lt;/strong&gt;&amp;quot; to several of the points I&amp;#39;ve made above. Yes, PhoneGap solves many of these problems. But how do
we define a PhoneGap application? The technology stack I&amp;#39;m using is that
of a mobile web application: HTML, CSS, JavaScript. However, the
distribution and discovery systems I am using are that of a native
application. PhoneGap application straddle the fence between the two
worlds.&lt;/p&gt;

&lt;p&gt;For those that don&amp;#39;t know, PhoneGap extends a WebUI. It will add certain
functionality to the JavaScript API. Access to the camera, microphone,
file system &lt;a href=&quot;http://docs.phonegap.com/en/1.2.0/index.html&quot;&gt;as well as many other wonderful features&lt;/a&gt;.
The PhoneGap developers were smart, they saw the W3C&amp;#39;s proposed API for
some of this and modeled the PhoneGap API after it. In fact, PhoneGap
should acts as a polyfill if certain functionality already exists.&lt;/p&gt;

&lt;p&gt;From a developer&amp;#39;s point of view, PhoneGap in most cases should be a no
brainer. I am most likely developing a web site alongside the mobile
application. The website is likely going to be sharing the
functionality of the mobile application. It makes sense if my
mobile application can share a technology stack with my web application.
I don&amp;#39;t have to employ a separate team to develop the mobile
application, and if you want to target more than one mobile platform
you&amp;#39;ll most likely have to employ more than one team.&lt;/p&gt;

&lt;p&gt;From our perspective PhoneGap gives us a
huge advantage. Why pay two teams to develop the same application when you
pay us once? Then when we hand off the team maintaining and developing
your website can also maintain and develop the mobile application. It&amp;#39;s
a no-brainer. In most cases.&lt;/p&gt;

&lt;p&gt;There are some serious issues with the PhoneGap project. The first of
which is the difficulty in reporting errors. This will hopefully change
now that the project is under Apache (as &lt;a href=&quot;http://wiki.phonegap.com/w/page/46311152/apache-callback-proposal&quot;&gt;Apache Callback&lt;/a&gt;)
but the project has been split into different Github repos for each
platform. So there is one for &lt;a href=&quot;https://github.com/phonegap/phonegap-iphone&quot;&gt;iOS&lt;/a&gt;, &lt;a href=&quot;https://github.com/phonegap/phonegap-android&quot;&gt;Android&lt;/a&gt;, &lt;a href=&quot;https://github.com/phonegap/phonegap-wp7&quot;&gt;Windows Phone 7&lt;/a&gt;, &lt;a href=&quot;https://github.com/phonegap/phonegap-blackberry-webworks&quot;&gt;BlackBerry&lt;/a&gt;, &lt;a href=&quot;https://github.com/phonegap/phonegap-webos&quot;&gt;WebOS&lt;/a&gt;, etc... they are all under separate development with very dedicated teams. If I find a common problem that affects all platforms (for example, &lt;a href=&quot;https://github.com/phonegap/phonegap-iphone/issues/280&quot;&gt;a suggestion I proposed on how PhoneGap currently implements its File API&lt;/a&gt;) I have to report this issue individually on each platform. This is a very inefficient process.&lt;/p&gt;

&lt;p&gt;The second is the same issue stated above with the camera. While PhoneGap does give us the access to the camera we are still stuck
with the same experience we will have with the W3C MediaCapture API: no
camera customization, this is just a delegation with a callback. You can
hack together the camera experience you want if decide to write some
native code.&lt;/p&gt;

&lt;p&gt;The third is lack of any background processing. When I throw my PhoneGap
app into the background it does nothing. It would be nice if we could
get a callback in the PhoneGap API that allowed us to kick off function
if the app is sent to the background. When it is up front again give us
another callback to halt the previous function.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://wiki.phonegap.com/w/page/36752779/PhoneGap%20Plugins&quot;&gt;Check out the &amp;quot;Limitations&amp;quot; section on the PhoneGap wiki for some
others&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;PhoneGap is fantastic (despite some of the criticism I&amp;#39;ve stated). We have
high hopes for the project now that it is accepted into Apache.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Perhaps &lt;a href=&quot;http://techland.time.com/2011/11/09/mobile-flash-abandoned-for-html5-adobe-surrenders-apple-wins/?iid=tl-main-lede&quot;&gt;Adobe&amp;#39;s announcement that they are abandoning Flash in
favor of HTML5 for mobile&lt;/a&gt; will be seen as the turning point when
mobile web application development begins to be a serious contender to
native. Or maybe it is just a coincidence that this buzz is happening
all at once. Either way, we&amp;#39;re happy
people are talking about this. Discussions, arguments, and all of the
attention in between are the best way to push this technology into the
future we all know is just a matter of time.&lt;/p&gt;

&lt;p&gt;As my friend &lt;a href=&quot;http://twitter.com/cykod&quot;&gt;Pascal Rettig&lt;/a&gt; says: It is a great time to be a web developer.&lt;/p&gt;
</content>
  </entry><entry>
    <title>DockYard is launched!</title>
    <link rel="alternate" href="https://dockyard.com/blog/2011/08/24/launch" />
    <id>https://dockyard.com/blog/2011/08/24/launch</id>
    <category term="announcement" label="Announcement"/>
    <published>2011-08-24 00:00:00</published>
    <updated>2016-03-24 15:11:19</updated>
    <author><name>Brian Cardarella</name></author>
    <summary></summary>
    <content type="html">&lt;p&gt;DockYard has officially launched!&lt;/p&gt;

&lt;p&gt;Hoo-ray!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/oRUq9T6.jpg&quot; alt=&quot;Hoo-ray!&quot;&gt;&lt;/p&gt;
</content>
  </entry>
</feed>
