Jekyll: Reading time without plugins

Estimated reading time of a post is a feature that became popular, I believe, with Medium.

There are plenty of Jekyll plugins that address this problem, but, if you want to deploy at GitHub Pages, you can't use those plugins (GitHub will run with the --safe flag).

So, I created a snipped of pure Liquid code to fix that.

So, the first thing we will want to do is get the word count. That's pretty, actually:

{% assign words = content | number_of_words %}

Now, we need to divide this number with something. This something is called Word per minute (WPM). According to Wikipedia, an average person can read 180 words per minute in a computer monitor. Now it became really easy to do the rest:

{{ words | divided_by:180 }} mins

But, what if the post has less than 180 words? Actually, even if it has more, 350 words, for instance, when divided by 180, will result in 1.94, Liquid will round it down to 1, so, the user will see "1 mins", which is weird. To fix that, we have to check if it has less than 360 words, because any number great or equal 360 will result in 2+ mins, which still plural.

That said, the solution is quite simple:

{% if words < 360 %}
  1 min
{% else %}
  {{ words | divided_by:180 }} mins
{% endif %}

So, to keep it organized, I put all this in a read_time.html in my _includes folder:

<span class="reading-time" title="Estimated read time">
  {% assign words = content | number_of_words %}
  {% if words < 360 %}
    1 min
  {% else %}
    {{ words | divided_by:180 }} mins
  {% endif %}
</span>

And then I just include it in my post layout:

{% include read_time.html %}

And it works, as you can see here. Hope you like! :beers:

Comment this post here.

OpenSourcing my blog again

Once upon a time, my blog was OpenSource. People liked it and forked it tons of times, but they never change some stuff (disqus, analytics).

I got irritated and closed it.

Now, I'm reopening it again. I improved the README so I hope now it's clear that people should change some stuff.

Hope you like it.

Comment this post here.

Jekyll with Sass

I followed @mdo recent article "Using Sass with Jekyll", and wanted to point out the results.

I'm using some version of Lanyon with some custom stuff. So, I had 4 CSS files:

Requests

Summing it up, ~22K. It's not a lot, but, thinking about mobile 3G plans that are shit (like brazilian ones), why not save some bytes and requests?

So, I moved all those files to a _scss subfolder, and changed their extensions to .scss instead of .css.

Then, in my public/css folder, I created a styles.scss like this one:

---
# Needed for jekyll...
---

@import "poole";
@import "syntax";
@import "lanyon";
@import "carlos";

Also, I added the following section to my _config.yml:

sass:
  sass_dir: _scss
  style: :compressed

Finally, changed my _includes/head.html to import only the new styles.css:

<link rel="stylesheet" href="/public/css/styles.css">

And boom! It worked. With this, my previously four requests of ~22K went to one request with 12.8K!

Request

Besides that, now I have all the power that Sass provides, in my blog, without any hacks. And it works on GitHub pages!

Comment this post here.

Flamewars

Or:

How I went from a annoying linuxfag to just a random guy who uses unix-based systems and drops a few jokes about how Windows sucks instead of try to convince each and everyone to use a real operating system.

When I first discovered Linux, I was amused. I thought "this is great! Why there is so few people using it?. I can change anything! I can compile things. I command! I'm root!" Then, young and dumb, I followed the linuxfag tribe and started to try to convince people to use Linux instead of Windows. No, really, I tried to convince designers to drop Windows and Photoshop and use Linux and Gimp instead. I don't really know why nobody beat me to death. I would do it if I wasn't me.

After some time, I realized that it's stupid to do this. This is all politics. Nobody gives a shit about Windows piracy - not even Microsoft. It's pretty much like a drug dealer, but worse: they let you use it for free and make believe that there is nothing else out there (do you parents even know what an operating system is?), then, they charge other people (or you, without you know it).

It's quite simple:

  • You are taught since you're a child how to click the "Start" menu and do things;
  • You'll go study somewhere (school, college, whatever) and work somewhere;
  • You'll need to use a computer;
  • You don't know anything else but Windows (alongside 90% of people);
  • Companies and Schools and Colleges and shit buy Windows and Office licenses;
  • MS wins, without bothering you and your piracy;
  • But, if you buy a laptop with Windows included, you are paying for it;
  • MS wins, again, without bothering you and your piracy.

As the majority uses Windows, people will do more softwares for Windows. That's why there is no Photoshop for Linux, for example. This is the most fundamental concept of economics: Supply and demand. To make it even worse, there is a concept misunderstanding (free software) that people who use Linux don't like to buy things - as they seem to like "free software", but, as fun as this may sound, they believe that people who download and install a pirate copy of Windows do - and will buy they shit.

My "Free software" argument was shit. People don't really care about other stuff I do, like security, freedom, ability to change things, compatibility with some development stuff and so on. People want it to work. People want it easy. People want to play the last FPS on the market. They don't want to battle a driver incompatibility error, neither learn how to use other music player, or deal with Wine errors while trying to emulate a Windows game.

The thing is, what works for me, might not work for you. For me it's easy to open a terminal and type commands, but not for my mother. I enjoy learning this kind of stuff, but most of my coworkers and friend don't.

We have to admit, Microsoft did a good job "addicting" everyone to their "drug". After that, I realized that people will use what they like more, it doesn't really matter what I say about it. The same goes about programming languages and almost any flamewar about technology out there.

So, I end this flamewar thing. The only thing I do now is a few jokes with my coworkers and friends about how they actually need to use a real operating system to do whatever they're trying to do. It's funny for me, even if most people don't get it. Anyways, I don't care.

Comment this post here.

My personal goals for 2015

Well, 2014 is now almost over, and I didn't accomplish most of things I planned to. I see now that I set goals almost impossible to accomplish in that amount of time.

Well, I did read one book per month, for example (well, actually, I read ~1,5 books per month). I do keep doing exercises. I did changed jobs. I learned a lot of stuff. But, I didn't bought a car (yet I'm paying it). I didn't keep studying music. I didn't learn and profit in 2 more languages. That's quite a shame.

So, for this new year, I will aim to "accomplishable" things, following something I read in "The Passionate Programmer".

So, those are my goals for 2015:

  • Read 2 books per month (it was quite easy to do 1,5);
  • Keep practicing my English;
  • Do at least one post every two weeks here;
  • Master one new programming language;
  • Continue to do exercises;
  • Stop paying rent and buy an apartment or something.

Except the last item, all of those are things that I want to actually keep doing the whole year. The last item, though, is the more challenging, because it involves money, and the current Brazilian economy may not let me do anything, so, even if it's a little out of my control, I will focus to try to do it.

Those are my goals, what about yours?

Comment this post here.

Lint your shell scripts

I will start this by quoting the bashstyle's readme:

Bash is like the JavaScript of systems programming. Although in some cases it's better to use a systems language like C or Go, Bash is actually an ideal systems language for many smaller POSIX-oriented or command line tasks. Here's three quick reasons why:

  • It's everywhere. Like JavaScript for the web, Bash is already there ready for systems programming.
  • It's neutral. Unlike Ruby, Python, JavaScript, or PHP, Bash offends equally across all communities. ;)
  • It's made to be glue. Write complex parts in C or Go (or whatever!), and glue them together with Bash.

My concern about that is the quality of the code itself. Like JavaScript, most people will just Google and do what they want in the first way that they found - quick and dirty. You can blame me too.

So, projects like bashstyle are important to set a common sense in how to do things using bash. The problem is that it's not automated.

A project that really helps with that is shellcheck. It's an executable written in Haskell, which can lint your scripts (in bash, zsh, and others). Sure enough, we can put this in a Continuous Integration system and watch it do the validation for us.

To make it easy to integrate shellcheck and travis-ci, I created a project called shell-travis-build. It is intended to be added as a submodule, like this:

git submodule add https://github.com/caarlos0/shell-travis-build.git build
cp build/travis.yml.example .travis.yml

Travis will always clone a project with its submodules before the build, so, it will always work. :beer:

I'm already using this in my dotfiles, and found some really stupid mistakes to fix. Sure thing, this is an awesome tool!

Wanna see it in the so said real world? Check my dotfiles build.sh and travis.yml files.

Happy hacking!

Comment this post here.

Don't use junit.framework

Every once in a while I see somewhere a wrong import to the old, deprecated junit.framework instead of org.junit.

I particularly believe they should remove this package and put it in a junit-compat jar or something... but, while they don't do that, we can avoid those old imports with 2 basic steps:

1. Replace all old imports with the new imports

This is pretty straightforward with a simple bash script:

#!/bin/bash
for file in $(git grep --break --heading "import junit." | grep java); do
  sed -i.bak s/junit.framework/org.junit/g $file
  rm -rf $file.bak
done

2. Don't accept it in new code

The second step is basically to break the build whenever someone try to use those old imports. A simple way to do that is using the restrict-maven-plugin.

An example of configuration for maven will look like this:

<plugin>
  <groupId>com.yamanyar</groupId>
  <artifactId>restrict-maven-plugin</artifactId>
  <version>0.6</version>
  <executions>
    <execution>
      <phase>process-classes</phase>
      <goals>
        <goal>restrict</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <continueOnError>false</continueOnError>
    <restrictions>
      <restriction>com.carlosbecker.* to junit.*</restriction>
    </restrictions>
  </configuration>
</plugin>

Sure it is a simple issue, which might never cause you problems, but, if one day the Junit team remove the old packages (probably soon), you will have a headache. Besides that, writing new code using deprecated classes?

Comment this post here.

Notify your team using Telegram

In an ideal world, applications will never go down, for example. In the real world, shit happens. Every second counts.

Let's take the example of a server going down for some reason (which shouldn't happen, ever). I want the team to be notified as soon as possible to mitigate the issue. To do that in a easy and free way, I decided to use Telegram.

Wait, wait... what is this Telegram thing again?

According to their website:

Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.

It's basicaly a Whatsapp-like messenger, with an open API and more security.

Wiring it up

First, install the telegram-client following their README.

Then, write your script. Mine looks like this:

#!/bin/bash
TG=/opt/tg

# $1: Server Name (used in the message body)
# $2: URL to test
# $3: Group/User to notify
function check() {
    wget -q $2 -O /dev/null
    if [ ! $? -eq 0 ]; then
        echo "msg $3 WARN: $1 IS DOWN!!!" | $TG/bin/telegram-cli \
            -k $TG/tg-server.pub -W
    fi
}

check "my server" "http://myserver.blah.fake.address/check" "Server1"
check "another server" "http://myserver2.blah.fake.address/check" "Server2"
check "Google" "http://google.com" "General"

Sure, you can script it in order to notify you about anything, including some business specific things, dependency on third-party systems... well, use your imagination.

I also added it to the crontab, so it will run every minute.

And, sure enough, it works:

telegram screenshot

Hope it helps!

Comment this post here.

Using JUnit Rules to simplify your tests

Have you ever wrote JUnit tests extending a class that does some before and after work, so you didn't have to repeat that code in various test classes? Well, I will not say that you have been doing it wrong, but, sure enough, you could do it better. How? Using JUnit Rules!

The Basics

Well, before we learn all that, let's start with the basics, shall we?

Timeouts

Let's take a simple example: Suppose that you want to set a timeout for all test methods in a given class, an easy way to do that is like this:

public class BlahTest {
    @Test(timeout = 1000)
    public void testA() throws Exception {
        // ...
    }

    @Test(timeout = 1000)
    public void testB() throws Exception {
        // ...
    }

    @Test(timeout = 1000)
    public void testC() throws Exception {
        // ...
    }

    @Test(timeout = 1000)
    public void testD() throws Exception {
        // ...
    }

    @Test(timeout = 1000)
    public void testE() throws Exception {
        // ...
    }

    // ...
}

Besides that you repeated yourself tons of times, if you want to change this timeout, you will have to change it in all methods. There is no need to do that. Just use the Timeout Rule:

public class BlahTest {
    @Rule
    public Timeout timeout = new Timeout(2000);

    @Test
    public void testA() throws Exception {
        // ...
    }

    @Test
    public void testB() throws Exception {
        // ...
    }

    @Test
    public void testC() throws Exception {
        // ...
    }

    @Test
    public void testD() throws Exception {
        // ...
    }

    @Test
    public void testE() throws Exception {
        // ...
    }

    // ...
}

Temporary Folder

Have you ever needed to do some test that uses File and/or needed a temporary file/folder? TemporaryFolder to the rescue:

public class BlahTest {
    @Rule
    public TemporaryFolder tempFolder = new TemporaryFolder();

    @Test
    public void testIcon() throws Exception {
        File icon = tempFolder.newFile("icon.png");
        // do something else...
    }
}

Expected Exceptions

Ever needed more control on exceptions? Try the ExpectedException rule:

public class BlahTest {
    @Rule
    public ExpectedException exception = ExpectedException.none();

    @Test
    public void testIcon() throws Exception {
        exception.expect(IllegalArgumentException.class);
        exception.expectMessage("Dude, this is invalid!");
        // do something that you expect to throw an exception...
    }
}

Custom Rules

That's neat, but... what if you need something else... something more "custom"? Well, you can implement your own rules by implementing the TestRule interface, for example, a Rule that init Mockito mocks (not very useful):

@RequiredArgsConstructor
public class MockRule implements TestRule {
  private final Object target;

  public Statement apply(Statement base, Description description) {
    return new Statement() {
      @Override
      public void evaluate() throws Throwable {
        MockitoAnnotations.initMocks(target);
        base.evaluate();
      }
    };
  }
}

To use it, you just need to declare that rule in your test class:

public class BlahTest {
    @Rule
    public MockRule mock = new MockRule(this);

    @Mock
    private BlahService service;

    @Test
    public void testBlah() throws Exception {
        Assert.assertThat(
            service.blah(),
            CoreMatchers.notNullValue()
        );
    }
}

External Resources

Returning to the example of this post's first paragraph, you can also have custom external resources rules by extending the ExternalResource class:

public class MyServer extends ExternalResource {
  @Override
  protected void before() throws Throwable {
    // start the server
  }

  @Override
  protected void after() {
    // stop the server
    }
}

I believe that this makes more sense with Integration Tests, though. Also, in this case, you probably would not want/need to start and stop the server before and after each test method, right? So, you can use the @ClassRule annotation:

public class BlahServerTest {
    @ClassRule
    public static MyServer server = new MyServer();

    @Test
    public void testBlah() throws Exception {
        // test something that depends on the server.
    }
}

Attention: Note that when you use @ClassRule, your rule instance should be static, just like @BeforeClass and @AfterClass methods.

Going Further

That's the basics that will save you tons of abstract classes and ugly code. I would also recommend you to take a good read at the junit wiki. If you have any question, don't exitate to comment bellow, I will surely try to answer them. :beer:

Comment this post here.

Exponential Backoff with Java 8

Exponential backoff is an algorithm that uses feedback to multiplicatively decrease the rate of some process, in order to gradually find an acceptable rate. - Wikipedia

I recently used this strategy in work to deal with another service that we need to integrate. Sometimes, the service will just refuse the connection, without any reason. If I keep pushing, it will, someday, accept it.

So, I used Java 8 Functional Interfaces to implement this in a not-so-ugly way, also using a Fibonacci's Sequence to increment the wait time:

The ExponentialBackOffFunction Functional Interface:

import java.rmi.RemoteException;

@FunctionalInterface
public interface ExponentialBackOffFunction<T> {
    T execute();
}

The ExponentialBackOff main class:

import static java.util.Arrays.asList;

import java.net.SocketTimeoutException;
import java.util.List;

import javax.net.ssl.SSLHandshakeException;

import lombok.extern.log4j.Log4j;

@Log4j
public final class ExponentialBackOff {
    private static final int[] FIBONACCI = new int[] { 1, 1, 2, 3, 5, 8, 13 };
    private static final List<Class<? extends Exception>> EXPECTED_COMMUNICATION_ERRORS = asList(
            SSLHandshakeException.class, SocketTimeoutException.class );

    private ExponentialBackOff() {

    }

    public static <T> T execute(ExponentialBackOffFunction<T> fn) {
    for (int attempt = 0; attempt < FIBONACCI.length; attempt++) {
            try {
                return fn.execute();
            } catch (Exception e) {
                handleFailure( attempt, e );
            }
        }
        throw new RuntimeException( "Failed to communicate." );
    }

    private static void handleFailure(int attempt, RemoteException e) {
        if (e.getCause() != null && !EXPECTED_COMMUNICATION_ERRORS.contains( e.getCause().getClass() ))
            throw new RuntimeException( e );
        doWait( attempt );
    }

    private static void doWait(int attempt) {
        try {
            Thread.sleep( FIBONACCI[attempt] * 1000 );
        } catch (InterruptedException e) {
            throw new RuntimeException( e );
        }
    }
}

Usage:

ExponentialBackOff.execute( () -> work() );

This will try to execute the work method incrementing the time between each call that fail with an expected error.

Comment this post here.