New Blog 2021

2021-05-01

I’ve not only stopped writing things on the blog, I also stopped updating its various workings, styles, etc. Time to change the latter, and see if it leads to the former. Knowing life, it probably won’t.

Why not WordPress?

WordPress has served me well since 2006. 15 years? Not bad – there are few things with this longevity in my computers. But I’ve grown afraid of it:

  • The interface keeps changing. I’m old and don’t like it when interfaces improve.
  • Everything is stored in MySQL. Fine, I can take a mysqldump every now and then? But what can I do with it really? And I have to actually keep running a MySQL server! If WordPress were able to use SQLite, I might’ve stuck with it.
  • PHP, WordPress… guess how often I updated them? Yes – how didn’t everything get hacked yet?

Why Jekyll?

I like versioning things with git. I like simplicity. I like plain text files I can just edit. Digital restraint or hipsterism?

I’ve used Middleman in the past, and now can’t update my tsumego website. Apparently my Ruby is too new for my dependencies, so I update the dependencies, and then run into a Thor issue, which also is tracked on Debian and Ubuntu, and I really don’t care about any of this and just want things to work. Jekyll seems to continue working. I hope it continues working for the next 10 years at least. And if it breaks, I’ve got everything in relatively plain html/markdown files and should be able to take it from there.

Comments

Your wonderful comments were often much more interesting than my posts, and I worked hard to preserve them. Unfortunately, I’m not sure how to make commenting possible without suck. Some options:

  1. Disqus, Facebook, etc: yes it’s easy, but where is the simplicity? I wanted more control and predictability and safe feelings, using a centralized third party to handle your precious comments would be downright irresponsible.
  2. The Jekyll resources page lists some options that allow commenting using GitHub issues: I quite like that a bit, but the end result looks dodgy – each commenter has to agree to give some random app the write access to their soul.
  3. The poor-man solution. As this is mirrored on GitHub anyway, just go and create a PR to add a comment? It’s not exactly user friendly, but hey, at least there’s a barrier to entry. I’ve written down instructions how to add comments. If GitHub ever goes away, the comments will be part of the repo and I can take them elsewhere. That, plus no one comments here anymore anyway.

Common addictions

2021-03-11

Many items of daily use have exactly the opposite effect to what’s desired. One’s body gets used to the thing, and then can’t do without, exacerbating any problems one might have started with.

In my particular case, the lip balm has been the worst offender. I started using lip balm quite young, my lips were dry and a lip balm immediately made me feel better. At some point during my use, my lips switched from becoming dry to simply burning. Suddenly, I had to apply the lip balm all the time, otherwise I’d get an immediate burning sensation. This was very annoying, but oh well, I just took a lip balm with me everywhere. Then one day it dawned on me that other people didn’t have this problem. I tried different lip balms, to no avail. Then one day, I stopped using lip balm. Within two days, the burning sensation turned into the much more bearable dry lips. After ceasing usage, my lips became ok after a week.

Things of daily use for which I’ve developed an addiction and managed to get rid of it:

  • Lip balm – the worst, avoid!
  • Nasal spray – I blame it for my prolonged colds. Perhaps three years ago, girlfriend told me not to use nasal spray when I had a cold, and I suffered a little at the beginning, but went through the cold quicker and I haven’t had much of a cold since. Coincidence? I don’t know…
  • Antiperspirant – Used one for one summer, smelled like a dead cat whenever I forgot to use it for a day. Afterwards, reeked for weeks. Never again.
  • Shampoo – I had to wash my hair every day otherwise my head would become oily and itchy. Some years ago on a yacht, Regina told a story about a woman who stopped shampooing her hair. I tried the same with great success: now that I only wash my head with warm water, it no longer feels the need to produce as much oil. Mind, I’m still bald.

Things I have not developed an addiction for:

  • Hand lotion – If you use hand lotion, I’ll show you my hands. You can admire the silkiness. I never use gloves when dealing with aggressive detergents etc.
  • That’s it! Can’t think of anything else I’m not addicted to. I’ll amend this later if I come up with something!

[This blog post brought to you by Diana. Diana said I should write a blog!]

Make Gnome on Ubuntu 20.04 usable

2020-10-06

Back when I hated Unity, I wrote down some steps to make it nicer. Well I’m still on Ubuntu (which might change soon – snaps suck), and these days like to hate on Gnome.

I’ve since moved some settings to config files, but most of the setup is still manual and will keep evolving as Gnome keeps breaking things.

Start by installing gnome-tweak-tool. Under “Windows”, choose “Focus on Hover”, perhaps tweak some other settings, and then install the Extensions.

Gnome ignores ~/.xsession, ~/.xinitrc etc, so under “Keyboard & Mouse”, choose “Additional Layout Options” and “Ctrl position” and “Swap Ctrl and Caps Lock”. Also “Switching to another layout”, “Two shifts together”.

Must have, without these I’d off Gnome:

  • Workspace Matrix – my virtual desktops must be in a grid. In settings, select “Show workspace grid in the overview”.
  • No Title Bar – Forked – Vertical space is precious, don’t take it away from me. There used to be “Pixel Saver”, then “No Title Bar”, and now “No Title Bar - Forked”. Gnome keeps breaking things, extension developers can’t keep up.
  • System Monitor Next – I really need to see what my system is doing. Same story as above, there are many versions, most no longer work.

Nice to have:

Sleep

2020-09-17

I’ve been having trouble with insomnia for several years. It came in waves, a couple weeks it was better, a couple weeks worse. I’ve been using a sleep tracking app to keep track of how bad I slept. I’d look at it and analyze everything and feel sorry for myself.

Say it was like 3 years and say I spent on average 2 hours a night not being able to sleep. That’d be over 2000 hours lost, and that’s probably a conservative estimate.

I always knew one had to get up regularly, but haven’t been doing it since probably 2012. I’d try to limit blue-light in the evening, and did all kinds of things which are tangential to good sleep. Anything but regular sleep schedule!

About two weeks ago I decided enough was enough, deleted the sleep tracking app, set up a “dumb” alarm for 7:07 every day of the week, and reduced total time in bed to something uncomfortably short (around six and half hours). For the past week I’ve been sleeping great, all thanks to these two things. I still have trouble getting up at 7:07, but that’s a short moment of discomfort compared to hours of insomnia.

There’s a wonderful page describing how to sleep better. I didn’t even need to do all that much to cure my terrible insomnia – just the basic basics helped almost immediately. I wonder, how else can I easily drastically improve my quality of life?

The joy of Elm

2020-05-02

Elm is a purely functional programming language for creating web frontend. It is strongly typed, largely influenced by Haskell – without some of the things that make Haskell difficult for newcomers, and with much better error messages.

I’ve recently written two small (~2k lines total) side projects in Elm. Writing code in Elm is an absolute joy:

  • It’s easy to get started and Elm is a simple language.
  • Very strong typing – seems somewhat stronger than in Haskell. Eg List.head is of type List a -> Maybe a and won’t crash on you in runtime – if the list is empty you get Nothing. If it compiles it usually works.
  • Elm has amazing error messages. They don’t just tell you what’s wrong, they try to explain why that could be and suggest how you could try to fix the error. I have never before encountered errors this helpful.
  • There’s Ellie – a wonderful online environment to play around and share snippets.
  • The Elm Slack is the most helpful and responsive community I’ve ever participated in.
  • Refactoring is a breeze – it compiles it works. I’ve never had a refactoring mess up things that worked before.
  • Yes Elm compiles to JavaScript, and I’ve never had to dive into the generated code.

That said, there are some potential drawbacks:

  • No higher kinded polymorphism: to map over a List, you need to use List.map, to map over Set, use Set.map. This is slightly verbose and sucks for the library developers, but isn’t a big problem for the end user.
  • Elm-land is an autocracy. Evan has been a very enlightened ruler, so this could also be seen as a benefit.
  • The development of Elm itself is intentionally slow: they try to get it right rather than get it out quick. Some things one would like in the standard library are external libraries. The repository of Elm packages is rather comprehensive.

Set DNS server in Ubuntu 20.04 Focal Fossa

2020-05-01

Set contents of /etc/systemd/resolved.conf to:

[Resolve]
DNS=45.90.28.239 45.90.30.239
Domains=~.

Apparently spaces are separators. Those are NextDNS servers in the example btw. NextDNS has not sponsored this post.

Then run: $ sudo service systemd-resolved restart

This was one of about two hundred million things that took me too long to figure out while setting up Ubuntu 20.04.


And in case you want to resolve single-label lookups, systemd-resolved don’t do that.

  • apt install dnsmasq resolvconf
  • Disable systemd-resolved
  • Set dns=dnsmasq in /etc/NetworkManager/NetworkManager.conf
  • Set nameserver 127.0.0.1 in /etc/resolvconf/resolv.conf.d/base
  • Restart all teh things

Three years of cold showers

2019-10-20

I don’t start my showers cold, but always end them so. I start the shower warm, then switch to hot, then at the end as cold as possible for about half a minute. In the beginning it was mildly uncomfortable, but I’ve become accustomed to it quickly. Showering in different places, I’m often surprised at the range of different temperatures of the coldest water available.

A cold shower really wakes you up. It closes your pores, which is good for the skin, and prevents heat loss. After a cold shower, you’ll always feel great about yourself.

Interestingly, ending with cold showers is perhaps the only positive habit I’ve built recently. I usually find forming habits challenging. This one didn’t require much work at all – usually I’m good at finding excuses, the easiest one being “I don’t have time for this”, which doesn’t apply here. Yes, I do have half a minute (and so do you, you’re reading this after all).

One year with Scala

2017-06-01

This is gonna be rambling personal experience. You have been warned.

A year ago I took a break from my work at Inviqa to learn Scala and functional programming. This has been a great decision, a most successful endeavour, and an amazing learning experience.

I’ve been stuck with PHP for a long time. Mind, at Inviqa we were doing as good PHP as one can. I learned lots about software engineering from a multitude of conference speakers and industry leaders. This was further helped by a very active learning & development department and a generous conference/learning budget. Still, it was PHP. The language sucks.

Learning Scala as a “better Java” kind of language was easy. Case classes, options, lots of easy wins. Learning functional programming… well, I’ve been reading the awesome Functional Programming in Scala book, and I’m still reading it one year later. Despite its hands-on approach and lots of hand-holding, it’s not easy for me to digest. Functional programming is hard.

I used to really like Python. I wrote about 50 lines of Python recently, and just couldn’t believe how difficult it was. One needs to explicitly write return to return values. When just trying things out, you don’t get quick feedback from the compiler. Either write tests or run your code – the former seemed like overdoing it for such a short program, the latter was tedious. Working with the collections was a pain.

Let’s have a look at an example. What we want to do: split a string on commas, then strip whitespace from each element.

In Python:
map(lambda i: i.strip(), re.split(‘,’, string))

In Scala:
string.split(“,”).map(_.trim)

The relative conciseness of Scala is nice, sure, but the Scala code basically follows the instructions: take a string, split on a comma, trim whitespace. Python is completely cryptic in comparison.

The main drawback of Scala is not the language but the ecosystem. SBT (Scala Build Tool) is powerful but often times incomprehensible. The compilation can be slow at times. Scala’s Play Framework is not nearly as polished as PHP’s Symfony. Replacing any piece of Symfony is just a dependency injection away. Replacing a component of Play is bordering on impossible, everything depends on everything and is mostly hardcoded. I wanted to do a really simple one-line change in Play Framework routing but had to give up.

Inviqa didn’t have as much interest in Scala as I hoped, so regrettably, I stopped working for them. Now I’m part of KwiqJobs (soon to be Swarms Technologies), an amazing startup. We turn people’s waiting time into a new resource for companies. Our tech team works remotely and we meet about once a month for a week. It’s lots of fun! Also we’re hiring! :)

ListMap in Scala

2017-05-17

You probably don’t want to use a ListMap. It has an interface of a Map, but is “powered” (that’s too good a word) by a List. Thus pretty much any Map operations you call on it will take ages. Consider using a LinkedHashMap instead – it will preserve both the element order and your sanity.

That’s me trying to blog more.

MySQL low cardinality index efficiency

2016-11-28

I’ve heard the opinion that indexes on low cardinality columns don’t work well. I set out to disprove that.

First, let’s create a table with a boolean column “active” and fill it with dummy data. Please note it includes a (default, B-Tree) index on the “active” column.

> show create table users\G
*************************** 1. row ***************************
Table: users
Create Table: CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`active` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `active` (`active`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

> DELIMITER ;;
> CREATE PROCEDURE insert_random(IN amount INT, IN percent_active INT)
    -> BEGIN
    ->   DECLARE counter INT DEFAULT 0;
    ->   myloop: LOOP
    ->     if (counter = amount) THEN
    ->       LEAVE myloop;
    ->     end if;
    ->     INSERT INTO users SET
    ->       name = UUID(),
    ->       email = UUID(),
    ->       active = IF(FLOOR(RAND() * 100) < percent_active, 1, 0);
    ->     SET counter = counter + 1;
    ->   END LOOP;
    -> END ;;
Query OK, 0 rows affected (0.00 sec)

> DELIMITER ;

> call insert_random(1000000, 10);
Query OK, 1 row affected (36.60 sec)

> select count(*) from users;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.18 sec)

We’ve inserted a million users into our table! That took some time. Please note the 0.18 seconds to count them all.

Now, let’s see how fast we can count the active users:

> select count(*) from users where active = true;
+----------+
| count(*) |
+----------+
|    99887 |
+----------+
1 row in set (0.04 sec)

Cool, pretty fast. Can you explain that?

> explain select count(*) from users where active = true\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: users
   partitions: NULL
         type: ref
possible_keys: active
          key: active
      key_len: 2
          ref: const
         rows: 208462
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)

Now let’s drop the index and run the test again:

> alter table users drop key active;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

> select count(*) from users where active = true;
+----------+
| count(*) |
+----------+
|    99887 |
+----------+
1 row in set (0.24 sec)

Wow, a lot slower… I’ve ran the selects a couple of times with consistent results to verify no caching was influencing the results. Let’s see the explain:

> explain select count(*) from users where active = true\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: users
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 912236
     filtered: 10.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

As you hopefully know: “Using index” good, “Using where” bad.

TL;DR A boolean column consisting of 10% TRUE and 90% FALSE queried for TRUE values using an index takes 0.04 sec, while not using an index takes 0.24 sec. The index speeds up the query by about a factor of six.

I’ve repeated the test with worse case scenario of a binary column split 50/50. 50% true, 50% false. The numbers are a bit less consistent, but generally around 0.16 for the indexed version and 0.24 for the unindexed version. Go indexes!