The First Feature is the Hardest | Upcase

Ben joins Joe and build out the first feature in a Rails application, from scratch. Learn our process for jump-starting new applications using Suspenders. We'll also use our first integration test to help sketch out the first interactions in the a...
This is a companion discussion topic for the original entry at

I like the use of the snippets @jferris. In your dotfiles it looks like you’re using snippetsEmu, but it seems that plug-in hasn’t been updated for several years, would you still recommend it?

It’s still working fine, but it does have some rough edges. I haven’t looked around in a long time to see if there are better snippets plugins, so it may be worth a check before using snippetsEmu.

Did you somehow automatically switch from full-screen terminal to a split between half-browser and half-terminal there? Or was that just video magic?

At what part (or parts) would you commit and push your progress?
In this case it’s a very straightforward example, but what would your commit strategy be in general? commit/push on every change, every time the tests are green, other times?

1 Like

I commit and push (to a new branch, not master) pretty often. It probably averages out to every 5-10 minutes.

I don’t really have a strategy–I just don’t want to lose any work.

Later, I squash all my commits down to one and write a great commit message. But while I’m working, I’ll write very short messages, and sometimes just commit with a message of “WIP” (work in progress).

Great video, guys.

@jferris when you finished with the feature, you mentioned that you would open a PR and then take the next feature/story/card from the list.

This is an interesting one for me and my team; I’m in two minds about whether someone should go on to the next card straight away, or wait for the first card’s PR to get merged.

What are your thoughts on this, guys? Is there a thoughtbot protocol here?

My strategy is similar to Ben’s.

Even if things are broke I don’t want to lose the work I will commit and push that up to a branch. At the end rebase it on master and squish any useless commits down and force push over my old branch, then submit a pull request.

This is mostly so my git repo is always in sync with my latests changes and if I switch to my home computer or to my work computer from my home computer I always have a copy of the code I need.

@jferris Why did you use :string when running rails g model? Rails infers a string type when none is supplied. Is there some advantage to explicitly declaring the string type?

Didn’t know that!

Still, I think it’s generally better to be explicit rather than relying on implicit behavior, unless that behavior is very well known.

1 Like

Agreed. Especially when doing a tutorial type of video.

Awesome! Just wanted to make sure I wasn’t missing out on some magic. :smile:

We try to have as little in flight as possible. This means that, before I start on another card, I’ll poke somebody to get a review and try to wait until it can be fully deployed, even if this means I need to pause work for a bit. I’ll generally use this down time to catch up on email and so on.

I’m very careful about having several stories going on at once.

1 Like

I didn’t know it was inferred!

1 Like

Nice - makes sense. Thanks, @jferris.

Hey guys,

Great video!

One thing I noticed was that in the feature spec you were hardcoding the content that you expected to see on the page (e.g. “Paste It!” and “can’t be blank”). I know that in one of TB’s blog posts titled Better Tests Through Internationalization (link), it’s recommended to use i18n in those places rather than hardcoded strings in order to make the tests more resilient to copy changes. For example,

click_on "Paste It!"

would become

click_on t("helpers.submit.paste.create")

@jferris @benorenstein Which one do you prefer to use in practice?

I have mixed feelings about the i18n approach… On the one hand, it definitely makes the tests less brittle; I can go in and make an innocuous copy change and not have to also change any of the tests. On the other hand, it abstracts (or completely hides away) the actual content so it’s unclear from looking at the test what it will be. This is especially troublesome if you don’t have exceptions turned on for missing translations because your test can pass while the user sees a “missing translation…” error on the page itself.

What does everyone think?

1 Like

We’ve gone back and forth on this a bit at thoughtbot.

The dominant opinion seems to be that using I18n in both views and tests is preferred. It does add some abstraction, but it prevents fragile tests or tests which no longer actually test anything. It also adds the benefit of not being tied to a particular language.

I used plain text in the video for the sake of clarify, simplicity, and time.

Makes sense. Thanks for the explanation Joe!

I agree, click_on t("helpers.submit.paste.create") isn’t particularly readable. But this might be an indication that the test could be written at a higher level of abstraction. If you focus on the business rule being described, then the exact text on the submit button is usually an incidental detail.

One way around this could be to move the call to click_on t(...) to behind a method, e.g. submit_paste.

Or you could use a Page Object, and call it with something like new_paste_form.submit.


@jferris I’d love to know how to do this too.