LoveWithFood Tech

LWF

Quick Thoughts on BEM

| Comments

Our team is using SMACCS to make the life of front end development shinier. Several days ago, my teammates introduced me to another awesome CSS methodology called BEM. I noticed it has some comparable points with SMACSS, but is slightly different.

Concepts

SMACCS BEM
Layout No direct equivalent
Module Block
No direct equivalent Element
State Modifier

Let’s review SMACCS first:

Layout rules divide the page into sections. Layouts hold one or more modules together.

Modules are the reusable, modular parts of our design. They are the callouts, the sidebar sections, the product lists and so on.

State rules are ways to describe how our modules or layouts will look when in a particular state. Is it hidden or expanded? Is it active or inactive? They are about describing how a module or layout looks on screens that are smaller or bigger. They are also about describing how a module might look in different views like the home page or the inside page.

BEM, on the other hand, has the following concepts:

Block: The sole root of the component.

Element: A component part of the Block.

Modifier: A variant or extension of the Block or Element.

Comparison

It looks like the State of SMACCS and Modifier of BEM are similar. However, the other components of the two methodologies have some differences.

SMACSS has Layouts and Modules. Layout represents the section of a page while Module represents a feature or part of a page.

In contrast, BEM has Blocks and Elements. BEM represents all things as Blocks, whether they are sections or modules. A block can contain multiple blocks. Element is the detail of a block.

BEM naming gives a stricter convention to define every corner of a page. Because it provides a standard which expresses the whole page in its language, it also gives us a way to unify the understanding of the page within a team. We can all use block, element and modifier to discuss the “feeling” of a page.

For example, “Look at the score box block. Its title element needs to be aligned center and its score element should be smaller” is easier to understand than “Look at the page, the text ‘some text’ need to be aligned center and the button should be smaller (only the developer knows the element that is implemented as a button)”. This is just a small example but we can imagine BEM would be helpful when we discuss a complicated page within the team.

Using BEM

Let’s see a simple example. Here is a demonstration which uses BEM. The block is score-box, and the element is score with some modifiers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.score_box {
  // some default block styles
}

.score_box__score--1 {
  // element score, mod 1
}

.score_box__score--2 {
  // element score, mod 2
}

.score_box__score--3 {
  // element score, mod 3
}

.score_box__score--4 {
  // element score, mod 4
}

.score-box--wider {
  // block mod 1
}

It’s clear what each class does, but we duplicate many score-box and score here. If we need to change the name, we need to change them all. It’s not hard but it breaks the DRY rule. So…

Let SCSS do the tricks

We can use SCSS to simplify the definition. We can assign selectors to local variables and use & to concatenate block selectors to element selectors:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$block: score-box;

.#{$block} {
  // some default block styles

  $element: score;

  &__#{$element}--1 {
    // element score, mod 1
  }

  &__#{$element}--2 {
    // element score, mod 2
  }

  &__#{$element}--3 {
    // element score, mod 3
  }

  &__#{$element}--4 {
    // element score, mod 4
  }
}

.#{$block}--wider {
  // block mod 1
}

The CSS looks more DRY now. However we should avoid nesting multiple level classes in order to gain more readability.

Ending

There is much more to SMACCS and BEM than what I have just written. However, I prefer BEM because it provides a way to express the page precisely and is easy to use with SASS. For a Rubyist and Rails fan, that’s not a problem :)

Refactoring in Code Reviews: My Experience

| Comments

I’ve found that refactoring helps me review someone else’s code. Before I started using refactoring, I could read the code, understand some degree of it, and make suggestions. Now when I come up with ideas, I consider whether they can be easily implemented then and there with refactoring. If so, I refactor. When I do it a few times, I can see more clearly what the code looks like with the suggestions in place. I don’t have to imagine what it would be like, I can see what it is like. As a result, I can come up with a second level of ideas that I would never have realized had I not refactored.

I found this gem when I was reading “Refactoring” by Martin Forwler. It was an interesting idea. Like any other programmer, I like to refactor. You’re turning messy code into a showcase of craftmanship. It’s a very therapeutic process.

Code reviews on the other hand can be stressful. You’re trying to understand someone else’s code primarily through reading. You’re also trying to understand two sets of code: the code before the pull request and code after it.

Thus, I had situations before when I just accepted code without truly understanding it. I would say something like “I don’t understand the code completely, but it looks well-structured and easy to change.”

Turned out those code weren’t easy to change.

So why not apply refactoring as a way to understand code while reviewing it?

Why did I decide to try refactoring during code reviews?

As mentioned, my primary reason for refactoring code during code reviews is to help me understand the submitted code better. Refactoring is our equivalent of the newpaper editor’s red pen; we can use it to correct code style issues, rename variables, extract missing methods and delete entire classes.

I have also come to the conclusion that it’s a fast way to do code reviews. In the same way that refactoring code before adding new features is faster in the long run than just slogging through ugly code, I believe that refactoring during code reviews is faster than reading someone else’s code, commenting about it, clarifying the comments with the code’s developer and waiting for the developer to make the changes.

By making the changes yourself and explaining the motivation for the changes in the source control commits, you have already communicated all that needs to be communicated with how you think the code should be. And with tests in place, you have demonstrated that the changes you wanted to add won’t break the code.

What and what not to refactor during code reviews

That being said, refactoring during code reviews doesn’t mean you can just change any code in the pull request. You have to follow one rule, the rule that defines what refactoring is. You don’t want to change behavior.

Refactoring means changing the internals of the program without changing its behavior. With code reviews, this would result in a refactored pull request being logically equivalent to the original pull request. With tests in place, you can be confident that you haven’t introduced bugs while making changes to the code. This allows you and the original developer to focus your discussions on the quality of the code changes, not on whether or not the code changes are valid.

What if you find bugs while refactoring? Should you fix them? Unless it’s the simplest of bug fixes, I think it’s best to let the original developer fix the bug. Two things are working against you: you don’t have the clearest understanding of the code and you’re working with an unstable/invalid environment. Finally, if you do try to fix the bug yourself, you and original developer might end up having different understandings of the code. That would make discussions about your refactorings more difficult.

Finally, there may be cases during refactoring when you notice that you can’t move forward without making major changes to the design of the code. For example, lately I reviewed a pull request where a dialog box was using Ajax to fetch the contents of the box. As I was refactoring the pull request, I had the idea that instead of Ajax, we could easily render the contents of the dialog box as part of the page. That way we don’t have to require JavaScript when running the acceptance test for the feature.

Since I felt such a change would be drastic for the feature, I asked the pull request developer first what he thought of the idea. After some discussion, we decided for him to do the change. I think that was for the best since he knew the pull request better than I did.

How do I incorporate refactoring during code reviews?

What I’m doing right now is to create a separate branch and pull request for the code review refactoring. This gives the original developer a chance to review and respond to the refactorings. The only exception I follow is when the pull request is already good enough to merge except for a few minor issues, like for example, incorrect indentation. In these cases, I go ahead and make the changes in the branch before merging them to the master branch.

I start reviewing pull requests through the acceptance tests. We use RSpec for our apps, so I take advantage of RSpec’s let, describe, and context features in order to understand the test code better. If I find any test variables confusing, I rename them or extract new let variables from them.

I then follow the flow of the acceptance tests, leading me to the implemented classes and their own tests. I concentrate on the major classes, refactoring them from the bottom-up. I start with code style issues, moving up to renaming variables, then extracting methods and finally to refactoring classes.

I try to keep commits as small as possible, essentially making a step-by-step record to how my mind was processing the code. These small step-by-step commits would help the original developer follow the code transformations easier.

What things did I learn by refactoring during code reviews?

Overall, here were some tips I learned when refactoring during code reviews.

  • Create a separate pull request for the code review. Give the original developer a chance to review and respond to the refactorings.

  • Refactor from the bottom up. It’s often easier to refactor a class one method at a time, building on the methods to eventually refactor the class itself. At the same time, such sequence of transformations tend to be easier to follow for the original developer of the code.

  • Prefer small commits. This way, the original developer can easily follow the sequence of the refactorings and confirm that they haven’t changed the logic of the original pull request.

Finally, it’s important that you’re willing to let go of the refactorings if needed. When you refactor code, you improve the code based on your coding principles. Sometimes though, those coding principles would differ from the principles followed by the original developer, or other developers in your team. The refactorings would eventually bring up those differences to surface.

And that’s okay. That’s how the process should work. Most of the time, you’d find common ground. But in cases when you don’t find common ground, don’t feel bad about shelving the refactorings you’ve worked on. You may think they were a waste of time, but they weren’t: the refactorings allowed you to understand the code.

Eventually, time is the best judge of any kind of code. More often than not, time is very forgiving, with good code and sometimes even with butt-ugly ones. Time can forget about code that we treat now as life-and-death issues.

However, when time does protest loudly about code being too difficult to handle, your experience with refactoring the code will allow you to have a more mature understanding of the code. You’ll be able to make better decisions on how to improve the code because of your experience with refactoring it.

Git_pretty_accept: Accept Pull Requests the Pretty Way!

| Comments

A few months ago, I suggested the Simple Git Branching Model and Best Way To Merge A (GitHub) Pull Request to Hendy, our CTO. We were using GitHub’s pull request feature for our code reviews, and as great as that feature was, it was turning our git history into, sorry for the pun, spag-git-ti. With the Simple Git Branching model, I was hoping for a more linear, more readable git history, with visible feature branches that can be easily reverted.

Hendy liked the idea, but felt that the workflow needed to be automated. With a script, accepting pull requests will be consistent and error-resistant.

And so, after several weeks of testing and usage, we’re happy to share git_pretty_accept.

git_pretty_accept is a ruby gem that rebases a pull request before merging it to master. The pull requests are always merged recursively to make branches visible in the history.

To accept a pull request, just run git pretty-accept BRANCH_NAME in the branch where BRANCH_NAME will be merged.

You can also provide a merge commit template .git-pretty-accept-template.txt to your project directory. This is great if you want your merge commits to follow a certain format e.g. you want your team to enter the issue link when accepting pull requests.

We wrote git_pretty_accept for our particular workflow. If you’d like to use the gem, here are a few things you’ll need to keep in mind. The script

  1. Assumes that your remote repository is origin. It doesn’t work yet with Github forks.
  2. Automatically removes the local and remote branch of the pull request once the pull request is merged.
  3. Complains if you accidentally try to accept the master branch.

Let us know what you think! Pull requests are most welcome.

Five Steps to Organize Your Translations by Resources

| Comments

Recently, we noticed that our translations were getting disorganized as more categories and subcategories were added like below.

1
2
3
4
5
6
7
8
9
10
11
12
13
# config/locales/en.en.yml
en:
  coupons:

# config/locales/activerecord.en.yml
en:
  activerecord:
    errors:
      models:
        coupons:

# config/locales/simple_form.en.yml
en:

As more resources (models, service objects) were being added, it was getting time consuming to keep track of all our translations. Furthermore, we were running the inherent risk of duplicating translations with a large translation file. Our solution then was to organize the translations by splitting each resource to its own translation file. In the next five steps, we will show you how you can reorganize your translation file making sure no translation is missing.

Step 1 – Back up your translations

Duplicate config/locales as config/locales_new

Step 2 – Slave through the sorting of your translations

1
2
3
4
5
6
7
8
9
10
11
12
# config/locales_new/coupons.en.yml
en:
  coupons:

  activerecord:
    errors:
      models:
        coupons:

  simple_form:
    labels:
      coupon

Well… We can’t help you with this one. You may also want to sort them in alphabetical order.

1
2
3
4
5
6
en:
  activerecord:

  admin:

  simple_form:

Step 3 – Install HashDiff gem

In your Gemfile under group :test, add require 'hashdiff'. You can read more about the gem here.

Step 4 – Convert locale directories to hashes

Add a TranslationsDirectory class under spec/support to convert config/locales and config/locales_new to hashes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# spec/support/translations_directory.rb
require 'hashdiff'

class TranslationsDirectory
  def initialize(path)
    @path = path
  end

  def to_hash
    result = {}

    Dir.glob("#{@path}/*.yml") do |file|
      if result.empty?
        result = YAML.load(File.read(file))
      else
        result = result.deep_merge(YAML.load(File.read(file)))
      end
    end

    result
  end
end

The method to_hash basically looks through the directory for all files ending with.yml and merges them into a single hash.

Step 5 – Write a test to make sure no translations are missing

Under spec/config:

1
2
3
4
5
6
7
8
9
10
11
# spec/config/locales_spec.rb
require 'spec_helper'

describe 'Difference between old locales and new locales' do
  it 'should be empty' do
    old_trans = TranslationsDirectory.new('config/locales')
    new_trans = TranslationsDirectory.new('config/locales_new')

    expect(HashDiff.diff(new_trans.to_hash, old_trans.to_hash)).to eq([])
  end
end

Once that’s done, run the test and watch it pass! If it doesn’t, HashDiff.diff(new_trans.to_hash, old_trans.to_hash) will generate an array showing duplicated, additional or missing translations.

That’s all from the tech geeks at Love With Food. Let us know what you think by leaving a comment below.

Setup

| Comments

This post is a step-by-step explanation of how this blog was set up. Octopress documentation explains all of this. However, if you keep reading here, you’ll get a method to create this exact blog.