Kartones Blog

Be the change you wanna see in this world

Recommended Articles - 2017/01/29

I wasn't planning to post again so quickly, but I've been reading quite a few interesting things and wanted to share the links before the list gets too big.

Customizing Pelican archives page

I wanted to personalize the blog archives page, as it was serving its purpose but was a bit messy:

Old archives page

What I wanted was to visually differentiate posts grouping by year.

Checking the theme's article.html code, it was a simple loop without any customization option:

{% for article in dates %}
 <li><a href="/{{ article.url }}">{{ article.title }}</a> {{ article.locale_date }}</li>
{% endfor %}

As the template system uses Jinja, I tried using set to create variables on template-render time:

{% set year = '1970' %}
{% for article in dates %}
 {% if not article.locale_date.startswith(year) %}
 {% set year = article.locale_date[:4] %}
 <li>{{ article.locale_date[:4] }}</li>
 {% endif %}
 <li><a href="/{{ article.url }}">{{ article.title }}</a> {{ article.locale_date }}</li>
{% endfor %}

But it backfired on me as it was not working as expected: each article had the date repeated. Why? Because I later found that Jinja variables are only available at the scope they are created, not at inner ones, so I was actually creating two year variables, one outside of the loop (always with value 1970) and another inside always set to article.locale_date[:4].

How then to proceed then to detect different years? The answer was simple: use an old but always resourceful index-based for loop:

{% for index in range(dates|length) %}
 {% set article = dates[index] %}
 {% if index == 0 %}
 <li>{{ article.locale_date[:4] }}</li>
 {% else %}
 {% set previous_article = dates[index-1] %}
 {% if not article.locale_date.startswith(previous_article.locale_date[:4]) %}
 <li>{{ article.locale_date[:4] }}</li>
 {% endif %}
 {% endif %}
 <li><a href="/{{ article.url }}">{{ article.title }}</a> {{ article.locale_date }}</li>
{% endfor %}

Now I finally can play with the articles and check their dates and detect when the year changes. And while I could avoid the article variables, being used at build time I prefer legible code. Here are the final results:

New format

5 Advices for job seekers

Recently, between interviewing people and talking with some friends about the interview process and what do we seek, I was thinking about quickly writing a list of the five things I think most people should do when searching for a new job. The following advices assume you're searching for a technical position (in software development, systems or the like), living in Spain, with not much but some professional experience.

  1. Learn how to sell yourself: Avoid extremes, either chatting too much about irrelevant stuff (dodging the questions asked) or being too shy and not giving enough detail or good examples (when you actually knew about the topic).

  2. Aim for tech-driven companies: I still have to find a single company where sales people don't become headaches for tech. I try to learn what, how and why they do what they do, but still outcomes vary from "I sincerely don't know what I'm selling" to "I don't give a fuck as long as I get paid my variable". Best scenario: no sales people and a CEO with tech background; Nice scenario: tech-driven roadmap driving the company; Everything else tends to eventually cause crunches, planification issues and chaos.

  3. Seek for a constant learning place: Companies mutate ("pivot"), roles change, code evolves (and gets replaced), colleages come and go, but what you learn is what will really help you in the future. You're the sum of your experiences, try to amass good ones by working on interesting projects with colleages smarter and different from you.

  4. But never forget the money: If you wanted to work just for the shake of what you do you'd be at an NGO or at home doing only opensource, so don't lower your requirements just because you're passionate about what you do. Ask for the amount you think is fair, or at least the market average, instead of selling your valuable time for peanuts.

  5. Equity and bonus are secondary at startups: It's so nice to speak about how Google, Twitter or Microsoft employees got very rich (including chefs and graffiti artists), but that's not the common scenario and outside of USA happens even less often. Most of the time your grants will mean nothing and your company won't be a huge success. Or if you're lucky and it gets bought, your common stock will be like a big bonus, maybe enough buy a new car, but not enough to buy a house. Unless you're entering a well stablished and usually mid to large company, negotiate first a decent base pay, then agree about the equity and lastly arrange the variable pay. Also ask for very specific terms/rules for evaluations, you'll avoid too subjective judgements.


  • While colleages come and go, it is very important to work at a nice environment with good teammates. Ninjas and rockstars might generate more problems than those they resolve, and a toxic environment will only drain your energy and patience (whenever it is a bad coworker, a bad manager, or something else).
  • English is critical: Not a perfect level but enough so you are able to understand conversations and communicate.
  • Who you hang out with is who you are: If you work at startups, you'll probably move between startups and get job offers mostly from startups. If you do consultancy or work at big companies, your contacts will be from those ecosystems, although it is more common for startups to peek for candidates also from big companies (sometimes people wants to change).

Recommended Articles - 2017/01/08

  • Raspberry Pi’s PIXEL Linux desktop now available for x86 PCs: Linux is fast, but working with such a limited hardware by default means this desktop is probably even faster and smaller, perfect for old PCs and laptops.

  • Speed of development always wins. Performance problems will (eventually) get engineered away. This is nearly always how technology changes -@seldo

  • Stack on a budget: List of services with free tiers of interest to developers.

  • The Power of Less Code: Nice read. Highlights:

    • Try hard to get rid of anything that isn’t needed
    • Code is a liability. You and your teammates are responsible for each and every line of code you produce
    • Less code means less complexity, which means less bugs, which means less unexpected outcomes in production
    • Simplicity is a prerequisite for reliability. The more complex a system, the more difficult it is to build a mental model, and the harder it becomes to operate and debug it
    • [Regarding code] complete it or delete it
    • The best code is no code at all
  • Why Percentiles Don’t Work the Way you Think: One of those must reads to avoid common misconceptions, very revealing. Some highlights I wanted to keep for the future:

    • Looking at your average response time is like measuring the average temperature of a hospital. What you really care about is a patient’s temperature, and in particular, the patients who need the most help
    • Percentiles are computed from a population of data, and have to be recalculated every time the population changes. Time series databases average over varying amounts of time, and don’t have the original population.
    • Think of percentiles as wave marks on a beach
    • A distribution shows the shape of the entire population
    • Heatmaps: essentially 3d charts where histograms are turned sideways and stacked together, collected over time, and visualized with the darkness of a color
  • Everything You Know About Latency Is Wrong: Related with previous point but regarding latencies, also some fallacies and mistakes commonly made.

  • If Your Boss Could Do Your Job, You’re More Likely to Be Happy at Work

    • People don’t quit bad jobs, they quit bad bosses
    • Employees are far happier when they are led by people with deep expertise in the core activity of the business
    • Bottom line: Employees are happiest when the boss knows what she or he is talking about, and that drives performance
  • Chabuduo! Close enough...: Chabuduo means leaving things unfinished, the opposite of craftmanship. It is a sad but interesting reading, because China might be "the land of the cut corner" but this slowly is happening elsewhere.

    • "The quota, set for everything from wordcounts for journalists to arrests for policemen, is a powerful spur to value nothing about the product except the speed of its production" Doesn't it sound like KPIs?
  • The empty brain: Your brain does not process information and is not a computer: Really interesting read as it is true I often hear that we're "just very complex computers", and readings like this opens your eyes to radically different points of views (and very well argumented).

  • Take It to the Limit: Considerations for Building Reliable Systems: interesting introduction to platform limits and backpressure.

  • If you can't trust your employees to work flexibly, why hire them in the first place?: Self-explanatory title.

  • Free Design books from O'Reilly: The trick is that some are more "reports" than real books, and a few have names that sound like buzzwords, but probably there's also relevant information.

  • Don't Get Trampled: The Puzzle For "Unicorn" Employees: Good advices for equity/stock options grants to employees.

Basic Nginx snippets

I've recently migrated my hosting, finally severing all remaining ties with .NET after rewriting some remaining small experients and projects with Python. As I now have a full Linux instance to manage (at Amazon Lightsail, wanted to try it and looks I'm sticking with it), I've had to improve my Nginx skills from "barely make a site run under a Docker container" to "configure multiple static and dynamic sites running on different subdomains on the same machine". This post is a small recollection of things I needed to accomplish.

Error log default location:


Subsites inside the same root server block (note that alias paths end with / while a server root path do not):

location /mysubpath/ {
 alias /my/path/to/mysubpath/;
 try_files $uri $uri/index.html =404;

Note: It is easier to follow the recommended rule of one /etc/nginx/sites-available/<name> entry per site or subsite instead of having a root path + location and then children location with different subpaths (using alias). I made it work even combining uWSGI and static sites but the config files were more complex, so I reverted to everything in its single file with a single server block.

Proxy uWSGI Python apps through Nginx using system sockets (and as a bonus, disabling default Nginx index file matching):

index wontmatch;

location / {
 include uwsgi_params;
 uwsgi_pass unix:/tmp/mysocketname.sock;

Protect password and similar sensible files from being served:

location ~ /\. { deny all; }

Making all path files have a default MIME type (CSV in the example):

location /mycsvs/ {
 types { }
 default_type text/comma-separated-values;

Protecting with basic authentication (sample tutorial):

auth_basic "Password required";
auth_basic_user_file /mypathtopasswordfile/.htpasswd;

Subdomain aliases:

server_name myalias1.name.com myalias2.name.com name.com;

Custom headers:

# only for success http responses
add_header X-Custom-Header a_value;

# all http responses
add_header X-Custom-Header a_value always;


location /cv {
 return 302 $scheme://portfolio.kartones.net/curriculumvitae/;


Fully removing Server header (not only Nginx version):

sudo apt-get update
sudo apt-get install nginx-extras

sudo vim /etc/nginx/nginx.conf

# inside `http {}` section add:
server_tokens off;
more_set_headers 'Server: ';

# Save, exit and:
sudo service nginx restart

GZip all statics (Javascript, CSS, etcetera), as by default only HTML and a few others get compressed:

sudo vim /etc/nginx/ngnix.conf

# Search for `gzip_types` and replace it by:
gzip_types text/plain text/css text/js text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/rss+xml image/svg+xml;

Cache expiration rules for static content: Include or adapt expires.conf inside http, server or location config blocks:

location ~* \.(?:rss|atom)$ {
 expires 1h;
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|zip|svg|webm|htc)$ {
 expires 1M;
 access_log off;
 add_header Cache-Control "public";
location ~* \.(?:css|js)$ {
 expires 1M;
 access_log off;

Serving Static Content: Official article, has interesting parameters if you serve big static content files (pdfs, zips and the like).

Previous entries