All posts by Abhishek Nagekar

IKBC MF108 V3 Unboxing And Review

Lenovo recently released their Thinkpad TrackPoint Keyboard II which I got super excited about. I could finally use a keyboard identical to my laptop’s while not having the laptop down on my desk, something that’s bad for posture and causes neck strain. But while looking at it, and some other options, I found some very pretty mechanical keyboards from brands that I had never heard of before. After a few days of searching the web and watching review videos, I decided to go for a mechanical keyboard instead of the Lenovo one. That’s the prelude to my journey of acquiring my first mechanical keyboard.

In this little article, I’ll talk about mechanical keyboards in general, and then talk specifically about the one that I chose. If you’re here just for the review of IKBC MF108, feel free to skip to the actual review.

What is a mechanical keyboard?

Unlike a membrane based keyboard found on most laptops and many cheaper desktop keyboards that we’re all familiar with, mechanical keyboards have a separate switch for each key. The switch action is similar to how a household electrical switch works; with a metal contact completing the circuit and registering a ‘click’. The kind of switch determines how the switch will react to being pressed (if it will make a click sound, or if it will have a tactile feedback, or if it will be heavy or light etc). I recommend this helpful video to get a better idea.

Mechanical keyboards are, generally speaking, more expensive than their membrane counterparts. They also last quite a bit longer, which is mostly due to quality materials that go into their manufacturing (Cherry claims 50 million clicks for the Cherry MX Blue switches). These keyboards can be customized with a wide variety of keycaps (the part that we touch with our fingertips while typing), switches (the part that actually registers the keypress – look at the image below) and the case (the enclosure for all of the components).

Cherry MX Blue, a popular switch from Cherry GmbH, a keyswitch manufacturer, in action. Notice the tactile bump on the way down – Source

Cherry MX switches beneath the keycaps on my IKBC MF108. The switches are transparent to allow for the backlight to shine through the switch’s case

Apart from the functional stuff, many of the mechanical keyboards have some sort of backlighting, even fully customizable RGB for aesthetics (and for typing in the dark if you need to look at certain keys).

IKBC MF108 V3

Okay, so let’s get to the meat of this article. My first mechanical keyboard and my thoughts after having owned it for the last four days or so.

Build quality

As soon as the delivery person hands you the package containing the keyboard, you’ll notice the weight. It is heavy, and not in the way of a sensation or feeling. It is literally heavy. How heavy, you might ask. Very. You’d probably not be able to pick it up with just one hand, and to someone unsuspecting, they might think it is glued to the desk if they try picking it up. It weights around 2.5 kilograms, and can cause serious injury if you drop it on your foot.

I made a very amateur unboxing video that’s embedded below. It shows what you get in the retail box and my initial impressions. I’ll link some timestamps in the video description so that you can skip to points of interest (it is a super long video of me fiddling with stuff).

Connectivity

It comes with a USB cable (USB-C port in the center on the back) and connected seamlessly to my laptop running Ubuntu. I don’t mind the lack of bluetooth/wireless. Would’ve been nice for some minimalistic desk setup, but I’m not very keen on such things.

Included accessories

A couple of accessories are included with the keyboard. Extra blue and red keycaps which are fairly low quality. A dust cover that doesn’t fit. The USB cable feels nice to the touch.

Overall I’d expect more quality in the accessories department for the price. On the bright side, the part that actually matters–the keyboard itself–looks uncompromised on quality. My unboxing video has timestamp to the point where I show all of these accessories.

RGB backlight

Key labels are nice and crisp, and it is a pleasure looking at the keyboard in dark

I loved the backlight. The lights can be controlled from the keyboard itself (brightness, per key color, prebuilt modes, stopwatch functionality etc) and thankfully doesn’t need a software (it is especially important if you don’t run Windows OS as most of these software are made exclusively for Windows).

Typing and click-y sound

I’m not super fast at typing, but could type at roughly the same speed as on my laptop at around ~65wpm.

Double shot ABS keycaps

This keyboard features ABS double shot keycaps. ABS is considered inferior as compared to PBT found on many other competing keyboards. This article goes into the difference in detail. Since this is my first keyboard, I don’t have a taste so can’t comment. Also, it is fairly easy to replace keycaps whenever you feel the need for change.

Price and purchasing – Shout out to CandyCase

It is retailing for EUR 190 at CandyKeys at the time of my writing, which is exactly what I paid for it. It is hard to get an ANSI layout keyboard, or any mechanical keyboard for that matter, here in Europe (slightly envious of my friends in the US right now).

I can highly recommend CandyKeys and its founder David (who handles the support@ email address). Super quick with the support and provides honest recommendations (didn’t expect that). The processing took a couple of days after payment and so did the shipping. Overall, very satisfied with the service so far.

Certain misconceptions about mechanical keyboards

Mechanical keyboards are only for gamers: They certainly are for gamers but a lot of people who work with computers, including software developers, also prefer these keyboards because typing on them is a joy.

Mechanical keyboards are loud: Some are, while others aren’t. There are tons of options when it comes to choosing the switches.

Mechanical keyboards are gimmicky: There’s no shortage of bright blinking mechanical keyboards that scream “look at me”, but there also are very professional beautiful keyboards that’d sit on your desk without a hint of the brilliancy unless someone decides to take a closer look.

Leopold FC660C

Mechanical keyboards will make your friends/colleagues go wow!: Most people will roll their eyes if you start talking about your beautiful keyboard or how nice the clicks sound. Probably the only people who’ll care are a bunch of random internet strangers over at r/MechanicalKeyboards, so make sure you post a snap of your new keyboard there.

Mechanical keyboards make you a 10x programmer (or gamer): I honestly think it doesn’t make that huge of a difference in your overall productivity. They certainly are a joy to type on and add character to your workstation, but is it worth spending hundreds of Euros on? Depends on what you currently have. Probably a secondary monitor would do you more good 🙂 But hey, if you can afford one and it brings you happiness everytime you look at it, go for it!

In closing

That’s it for my keyboard review article. I hope you found it useful. Your first keyboard doesn’t have to be super expensive. There are plenty of good quality keyboards in 60% or TKL sizes (more on sizes here: keyboardco.com) that would’ve been my first priority had they been in stock. Ducky, Leopold, Anne Pro are some of the brands I kept hearing about all over the place (perhaps good marketing?) so do check them out.

Before deciding on the switch type, I went to a nearby electronics store to try the different switches on the keyboards on display there. I’d recommend you do the same if this is your first time, just like me. If you have any questions or comments, feel free to write me an email.

Thank you for reading (and watching)!

So we’re making it a thing now? 6th Anniversary Of Blog

I wrote a blog birthday blog post last year, and the year before that and for whatever reason, one after the first year but none in between. So I think we can really say I’m making this a thing going forward. But that’s okay, as there’s something happening around this time every year. This year our senses are clogged by the news from the pandemic going on around the world which I touched upon a bit back in April.

Compared to April, things are much better right now here in Germany. We can go out and meet friends, eat at restaurants and shop for our favourite stuff. Life’s slowly getting back to normal, although there’s still that element of fear of catching the virus. Things aren’t as good in India, so it is anyone’s guess when I get to visit home next ‍♂️

As for my blog, this year wasn’t super active apart from a few posts and some cosmetic changes to the template. An interesting moment was a blog post getting featured in RealPython‘s newsletter! I’m quite proud of that.

I want to move the blog away from Jekyll, maybe to something Python based. Don’t get me wrong. I love Jekyll on Github Pages, but it is just too straightforward with rarely any problems to fix. I want something that’d break, allowing me to fix things and learn. But all of that is still to happen. Hopefully I find a stretch of time to finally make the move to a different blogging platform in the near future.

As for the rest of the year, I plan on making my workstation a little better, so expect small tech gear reviews here and there from the purchases I make. You can also expect more on Python programming and infosec as that’s on the agenda. So yeah, that’s it for this blog birthday celebration on a slow lazy Sunday afternoon. Cheers, I’ll see you in the next one.

Thank you for reading!

Logitech G305 Gaming Mouse Review

I was looking for an ergonomic mouse for my workstation upgrade (this mouse is one of the many things I’m adding to my work/hobby setup) and stumbled upon a lot of expensive gaming mice with RGB, scroll wheel and other fancy stuff. But I wanted none of that, just a mouse that’s good to hold, wireless but not Bluetooth, and is fairly accurate with a couple of extra buttons that can be customized to custom actions. I stumbled upon G305 from Logitech which had their premium HERO sensor with 12,000 DPI and good battery life. It has good reviews on Youtube and Amazon DE and was fairly cheap at EUR 43.

Initial impressions and build


In a nice little box, we find the mouse itself along with colorful paperwork, a Logitech sticker, USB-A extension and a Duracell AA battery. The mouse had the USB receiver inside it. After inserting the battery into the mouse, it does become a bit heavy. I like how solid it feels, but apparently more weight is bad when it comes to gaming mice. I’ve been away from both, gaming and physical mice for about 7 years now, so it was good to know, and is something to consider if you’re actually going to game with it.

No RGB

Another thing to note is that many gaming mice, even the ones half the price of this (albeit from no-name brands), come with RGB lighting. This one doesn’t but that’s not a problem for me.

Pointer speed toggle


There’s a button right behind the scroll wheel that changes the speed of the mouse pointer speed. It has four levels, and each level has a different colored LED indicator that lights up when it is toggled. Pretty sleek and handy.

Utility buttons


There are two utility buttons on the side which don’t do anything by default on Ubuntu (they did navigate to the next/previous tab in Chromium by default though). I used xev to find their button codes and then xbindkeys to bind them to toggle previous/next workspace in Ubuntu with the following

# in .xbindkeysrc
"xdotool set_desktop --relative -- -1"
  b:9

"xdotool set_desktop --relative 1"
  b:8

Install xdotool if you don’t have it already.

In closing

I am really enjoying this mouse, and have no problems so far. It is nice to have the Thinkpad clit mouse when typing/working and using the mouse when casually surfing the web (like browsing Youtube). I’ll post a little review of the new keyboard soon and if you’d like to know when I do, you might want to subscribe to the RSS feeds of my blog.

Chess – Basics

So recently I got interested in Chess, and by recently I mean 6 months ago. I learned some important beginner’s lessons along the way and I planned to document them in non-technical language in this article.

I’m assuming you know the very basics, like how the pieces move and what castling is, which is exactly how much chess I knew when I started. If not, go outside (on the internet) and learn the basics. Then create an account on lichess.org or chess.com and play around 10 games with other people. Then come back to this article.

So assuming that we’re on the same page, let’s start!

Stages of the game

A chess game can be visualized to happen in three stages; Conveniently–start, mid and end game. You can be mindful of what stage the game is in as there are certain things you can do in each stage to give yourself a slight edge in the game.

When you start, you try to develop the pieces as quickly as possible and castle. That means all pieces are ready to jump into action; whether attack or defence, and your king’s safety is ensured.

Midgame, depending on your position, you exchange pieces and try to get a better position. Make sure you’re either up material (pieces or pawns), or you have a better hold of the position and control more space on the board.

Endgame is when both sides go all out using whatever positional advantages they’ve created previously. It is also common for endgames to just have king and pawns, maybe a minor piece as well. In this case, both sides try to push their pawns and promote them to Queens (or any other piece but usually the Queen, and the first side to do it usually wins).

Pre game

Know value of the pieces: Not all pieces are as valuable. Pawns are unit value, that is 1. Knights and Bishops are 3, Rooks are 5 and Queen is 9 units each. When exchanging pieces, these values should be taken into account. It generally doesn’t make sense to sacrifice a Rook for a Bishop. Of course, there are times when you’ll want to do it (especially if you have a forced checkmate in place).

The value of your pieces changes depending on your position and the stage of the game. You can read about it on Wikipedia but you will also learn these things intuitively once you have enough games under your belt.

Starting tactics

Castle early, ensure king safety before anything: I used to frequently go for material (i.e. trying to win pawns or pieces) and space before castling which generally doesn’t end well. Once your opponent is done developing their pieces and castling, you’ll end up playing a very defensive game if your king is in the center of the board with undeveloped pieces.

Develop pieces as early as possible: Move all pieces out of their initial position, ready for attack or defence and connect rooks early in the game.

Don’t move the same piece twice in opening: In general, you should avoid moving a piece more than once in the opening as the goal is to develop pieces fast. Of course, exceptions are when your piece is attacked or if the other side offers a gambit (a pawn or minor piece sacrifice to gain positional advantage).

Develop Knights before Bishops: Another general rule of thumb as both Knights can develop and simultaneously control central squares which is usually a good idea.

Rooks work better when connected: Rooks are developed when they’re connected (both Rooks are defending each other). Another common tactic is to double rooks on an open file (a column on a Chess board without pawns) to mount a powerful attack.

Doubled Rooks on an open file are very powerful in infiltrating enemy territory

Aim for center control: It is generally a good idea to control the center four squares of the board. There are exceptions, however, as with certain openings we can aim for control over one side of the board and continue our attack from there.

The highlighted squares are important and you should try to gain control over them

General tactics

Don’t keep pieces in pin: If your piece or pawn is pinned, meaning a more valuable piece is behind it, it is good to unpin the piece (move the piece that’s behind it). This is especially true with king. You don’t want your king to be on the same file as your opponent’s Rook or Queen, and same diagonal as your opponent’s Bishop. If the other side brings their Rook to the same file as your King or Queen, move it away even if there are pieces in between.

White to play: The d pawn (pawn on ‘d’ file) cannot capture the Knight as the Queen is hanging and the Rook on d8 is xraying it. It is best to unpin (get away from the Rook’s file or Bishop’s diagonal) as soon as possible.

A piece that has moved a lot is worth more than an unmoved piece: If your knight has been moving around the board, it is generally in your opponent’s favour if they manage to exchange your active piece for their dormant piece.

A piece that covers more area is worth more than a piece that covers less area: Similar to a previous one, if your Bishop covers and controls a beautiful diagonal, your opponent might want to get rid of it by exchanging their unused piece for your beautiful Bishop. Try to protect your active pieces.

If you control more space, don’t trade pieces: If your pieces control a lot of space on the board, you should avoid trading pieces.

If you’re crammed, exchange pieces to create room: Conversely, if you’re crammed by your opponent, try forcing exchange of pieces and pawns to create some room for your pieces to develop.

If defending, defend a piece as many times as it is attacked: If you want to defend a piece or pawn, defend it as many times as it is attacked.

If attacking, attack a piece as many times as it is defended plus one: If you’re the one attacking, mount an attack such that the other side runs out of ways to defend.

Two pieces are better than one piece: It generally doesn’t make sense to sacrifice a Bishop and a Knight for a Rook, or two Rooks for a Queen. It is, generally speaking, better to have two pieces instead of one (use the point value of pieces to decide if the exchange makes sense, but remember that active pieces are more valuable than passive ones).

Avoid back rank issues: If you don’t defend the last rank (where your king usually resides), a Rook from your opponent might simply deliver a checkmate (since the pawns in front of your king might be unmoved leaving no room for your king to escape).

In this position, if White isn’t careful, the Rook on a8 can deliver a checkmate which is why you must make an escape route for your king or have a defender on the last rank

Capture with pawns towards the center: Generally, if you capture with a pawn, you want to capture towards the center of the board if that’s an option.

Knights belong in the center of the board: It is usually not the best idea to move the Knight to a corner of the board as they cover fewer squares from there. They say Knights on the rim are dim. This applies to most pieces but especially the Knights.

As you can see, a centrally positioned Knight controls many more squares than a cornered Knight

Avoid creating pawn islands: An isolated pawn is one that isn’t connected with your other pawns. Such pawns are liabilities and weaknesses, and hence should be avoided (or sacrificed for positional advantages). In general, try to have as few pawn islands as possible.

Black has 2 pawn islands and white has 4. Black is to be preferred here.

Avoid doubled pawns: Doubled pawns are two pawns on the same file. As with pawn islands, they are weak and can become a liability in the endgame. It is said that a Rook’s favourite meal is a doubled pawn and is best to avoid doubling your pawns.

Grab any open files for your Rooks: When pawns are traded, they leave behind open files. Be quick and place a Rook behind an open file to gain control over the entire file. Later you could also double Rooks on the same file for a powerful attack.

A Rook on an open file covers a lot more square compared to a rook behind pawns

Avoid exchanging the fianchettoed Bishop: The fianchettoed Bishop is supposed to defend the weaker squares around the King and control a long diagonal. You shouldn’t exchange it in early or mid game if that’s an option.

The Bishop on g2 does a nice job of defending the weaker squares around your King’s castle.

Know thy Bishops – Bad Bishop vs good Bishop: A bad Bishop is one that’s obstructed by your own pawns, ending up looking like a pawn itself (and not controlling much space). A good bishop covers a nice long diagonal.

Notice how Black’s Bishop is nicely controlling a diagonal while White’s Bishop is essentially a pawn

Bishops and Knights are equal, except…: Bishops and Knights are both 3 points, but Bishops are usually preferred when the board has few obstacles, while Knights are preferred when the position is very tight. In general, a Bishop pair is always something you’d want to save if you can.

Be mindful of forks: Forks come when two pieces are attacked by an opponent’s piece and we lose one of them anyhow. Knight forks are common and can be tricky to spot. A fork that comes with an attack on the King and the Queen is called a royal fork.

Here, black will lose a Rook
A royal fork

Next steps

From here, you should learn some of the openings and endgames. Openings will help you quicky get to a position where all of your pieces are mobilized and ready, and also know what’s on your opponent’s mind depending on what they play.

Endings are important to know how to actually win most games. Many games might not end with you having a bunch of heavy pieces storming your opponent’s king. On the other hand it would be quiet and tactical, and you should know how to best make use of the couple of minor pieces and pawns that are on the board.

In closing

Hope you enjoyed this article on some beginner tips for levelling up in Chess. If you’d like to play Chess with me, challenge me on lichess at lichess.org/@/abhn.

Thank you for reading!

Concurrency In Python For Network I/O – Synchronous, Threading, Multiprocessing and Asynchronous IO

In this article, let’s look at some of the ways to do batch HTTP requests in Python and some of the tools at our disposal. Mainly, we’ll look at the following ways:

  1. Synchronous with requests module
  2. Parallel with multiprocessing module
  3. Threaded with threading module
  4. Event loop based with asyncio module

I was inspired to do this because I had a task at hand which required me to write code for a superset of this problem. As someone who can write basic Python, I implemented the most straightforward solution with for loops and requests module. The task was to perform HTTP HEAD requests on a bunch of URLs, around 20,000 of them. The goal was to figure out which of URLs are non-existent (404s, timeouts and so on) in a bunch of markdown files. Averaging a couple of URLs a second on my home network and my personal computer, it would’ve taken a good 3-5 hours.

I knew there had to be a better way. The search for one lead to me learning a few things and this blog post. So let’s get started with each solution. Do note that depending on the hardware and network, it might go up and down quite a bit, but what’s interesting is the relative improvements we make going from one method to the next.

Synchronous code with requests module

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
import time
from helper.urls import urls
import requests


def make_request(url):
    try:
        res = requests.head(url, timeout=3)
        print(res.status_code)
    except Exception as e:
        print(e.__class__.__name__)


def driver():
    for url in urls:
        make_request(url)


def main():
    start = time.perf_counter()
    driver()
    end = time.perf_counter()
    print(f'Synchronous: {end - start:.2f}')


if __name__ == '__main__':
    main()

If you try to think what you’d do if you had to check 10 URLs if they work, and write that process down in pseudocode form, this approach is pretty much what you’d get. Single threaded and synchronous, just like a human.

This script fetches 800 random URLs from a different file, makes an HTTP HEAD request to each, and then times the whole operation using time.perf_counter().

I ran all the tests on a Raspberry Pi 3 running freshly installed Ubuntu 20.04 LTS, but I don’t intend on making this scientific or reproducible, so don’t take the results at face value and test it yourself. Better yet, correct me and tell me how I could’ve done it better!

Synchronous code took 536 seconds to hit 800 URLs

With that we have our baseline. 536 seconds for 800 URLs that we can use to compare our other methods against.

Multiprocessing with multiprocessing module

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
28
29
import time
from helper.urls import urls
import requests
from multiprocessing import Pool
from multiprocessing import cpu_count


def make_request(url):
    try:
        res = requests.head(url, timeout=3)
        print(res.status_code)
    except Exception as e:
        print(e.__class__.__name__)


def driver():
    with Pool(cpu_count()) as p:
        p.map(make_request, urls)


def main():
    start = time.perf_counter()
    driver()
    end = time.perf_counter()
    print(f'Multiprocessing: {end - start:.2f}')


if __name__ == '__main__':
    main()

My Raspberry Pi is a quad core board, so it can have 4 processes running in parallel. Python conveniently provides us with a multiprocessing module that can help us do exactly that. Theoretically, we should see everything done in about 25% of the time (4x the processing power).

Multiprocessing solution took 121 seconds

So a bit less than 25% but if I run both the scripts over and over again, the average converges to a ratio of roughly 4:1 as we’d expect.

Threading with threading module

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
28
29
30
31
32
33
34
35
36
import time
from helper.urls import urls
import requests
import threading


def make_request(url):
    try:
        res = requests.head(url, timeout=3)
        print(res.status_code)
    except Exception as e:
        print(e.__class__.__name__)


def driver():
    threads = []
    for url in urls:
        t = threading.Thread(target=make_request, args=(url,))
        threads.append(t)

    for t in threads:
        t.start()

    for t in threads:
        t.join()


def main():
    start = time.perf_counter()
    driver()
    end = time.perf_counter()
    print(f'Threading: {end - start:.2f}')


if __name__ == '__main__':
    main()

With threading, we essentially use just one process but offload the work to a number of thread that run concurrently (along with each other but not technically parallel).

Threading code runs in 41 seconds

Threading runs much faster than the multiprocessing, but that’s expected as threading is the right tool for network and I/O bound workload while multiprocessing suits CPU intensive workloads better.

Short detour: visualizing threading and multiprocessing

If you look into your system monitor, or use htop like I have in the following images, you’ll see how multiprocessing differs from threading. On my dual core (with 4 threads) personal computer, multiprocessing creates four processes (with only the default one thread per process), while threading solution creates a much larger number of threads all spawned from one process.


Code running the multiprocessing [above] and threading [below] solution as viewed through htop

This helped me better understand the difference between threads and processes on a high level and why threading solution is much faster for this particular workload.

Asynchronous code with asyncio module

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
28
import time
from helper.urls import urls
import httpx
import asyncio

async_client = httpx.AsyncClient()

async def make_request(url):
    try:
        res = await async_client.head(url, timeout=3)
        print(res.status_code)
    except Exception as e:
        print(e.__class__.__name__)


async def driver():
    await asyncio.gather(*[make_request(url) for url in urls])


def main():
    start = time.perf_counter()
    asyncio.run(driver())
    end = time.perf_counter()
    print(f'Async IO: {end - start:.2f}')


if __name__ == '__main__':
    main()

Finally, we reach Async IO, sort of the right tool for the job given its event driven nature. It was also what sparked my curiosity in the subject in the first place as it is quite fascinating, coming from the event driven JavaScript land, to find an event loop in Python. [Read: Callbacks And Event Loop Explained and Event Driven Programming]

Asynchronous IO code ran in 11 seconds

Clearly this task is made for this approach, and the code looks surprisingly simple to understand which is a plus.

In closing

That’s it for this little adventure in Python land I sincerely hope you enjoyed it. If you find any corrections and improvements in the above text, please write them to me. It will help me get better at Python (and writing )

Thank you for reading

Buying A Lenovo Thinkpad X230 In 2020

I upgraded from my Lenovo Thinkpad T440 to a Lenovo Thinkpad X230. That sounds more like a downgrade, you might say, but it isn’t. Well, not in most cases for me, that is.

Hopefully. We’ll see.

In this little article I’d like to outline why an X230 in 2020 and if it could be your next daily driver.

First, enjoy the pictures and specifications

X230


So why buy an X230 in 2020?

Let’s dive straight into the meat of this article. Why buy an 8 year old laptop and not something new? There are a bunch of reasons that I can think of, not all as important but worth mentioning nevertheless, so let’s look at each of them in brief.

  • Cheap: I don’t mind paying for quality, but ironically, some of the best quality laptops out there are in the refurbished market. I really like the new X1 carbon and the Dell XPS 13 but I feel like the price premium is a bit disproportionate given what you get in return.

  • Upgradable: A user replaceable screen, keyboard, trackpad, RAM, storage, PCIe WWAN (cellular 3G/LTE), battery and god knows what else. RAM tops out at 16GB at 1600Mhz, SSDs upto 2TB at SATAIII supported, X220 classic keyboard and trackpad swap, IPS screen replacements available for EUR 60-70 and the list goes on. Since my Macbook Pro’s screen broke recently and was given a EUR 569 quote for the replacement, you can tell I appreciate cheap, user serviceable spare parts.

  • Practical: This isn’t one of those enthusiast laptops that you buy out of sheer impulse and idealization, and then find very inadequate for normal computing. With 16GB RAM and a 35 Watt i5-3320m processor, I have absolutely no problem running tens of tabs on Firefox, a Webstorm instance, dev server, Slack and Spotify simultaneously. It also has a Display Port and projects to my Dell Ultrasharp display at native 2560×1440 QHD resolution. If you’re into gaming, you could do that with an external GPU via the Express card slot.

    X230 (i5-3320m) vs T440 (i5-4300u) vs Macbook Pro 2017 (i5-7360u) — As you can see, the processor isn’t much slower than a much more modern machine, and actually faster than the T440, which is a generation newer than the X230. Source
  • Driver support: With an old machine like this one, drivers support is usually very good. I installed Ubuntu, and every thing worked out of the box from simple things like Wifi and Bluetooth to fingerprint sensor, and mobile broadband.

  • Build quality: Something we just expect from the Thinkpad lineup, especially the old Thinkpads. If this machine has survived 8 years of use, it’ll probably survive a few more. Unfortunately, you can’t say the same about many laptops in the same EUR 150-350 price segment.

  • Hardware & I/O: Thinkpad keyboards are usually good with ample key travel. You could opt for an X220 keyboard swap for the classic 7 row keyboard layout. What’s also great is the wide array of I/O option you get on board; Two USB 3.0s and one USB 2.0, mini display port, VGA port, Express card, ethernet port, SD card reader, combo headphone jack, fingerprint reader, hardware wireless kill switch; I think I’d miss a full sized HDMI, but that’s asking for a bit too much at this point.


  • Community & support: The Thinkpad community on Reddit is great for asking queries and upgrade suggestions. Having an old laptop means most issues are well documented and it is unlikely you’ll hit a novel roadblock if you don’t do anything fancy with your computer. I’ve been a lurker on this sub ever since getting the T440, and I knew one cannot go wrong with the X230.

Why not to buy a Thinkpad X230?

Of course, as you can imagine, I’d not recommend this laptop to everyone out there. Here are some of the reasons for that.

  • No warranty: If the thought of buying a device without warranty makes you sweat, this isn’t for you. Yes, you could get seller’s warranty on Ebay, but it is still not a manufacturer’s warranty.

  • Form factor: It is a small lightweight laptop, but not the smallest, lightest or thinnest. Most ultrabooks these days will be lighter and thinner, like the Dell XPS or Thinkpad X1 Carbon.
  • Battery life: You could get a 9 cell battery with the X230, but it will still not match that of a modern ultrabook thanks to the improvements in energy efficiency.
  • Need for tinkering: If you find this laptop for cheap, chances are you’ll have to do a few upgrades before it becomes usable (at least if you plan on making it your daily driver). If you aren’t comfortable with opening laptops and installing upgrades, it is better to buy either a fully upgraded machine or find a IT nerd friend who would do it for you.
  • Limit to upgrades: There’s often a limit to what upgrades you can do, and given this isn’t a new laptop, that limit isn’t that high. And all these upgrades cost money, of course. You shouldn’t spend a lot of money upgrading only to find out this still isn’t the laptop for you, regretting not getting a new computer in the first place.
  • Specialized usecases: Goes without saying, but if you definitely need a modern GPU for working or gaming, or a fast CPU for specialized needs, then this isn’t a laptop for you. But in that case you probably already know that.

What’s wrong with the T440? Avoid these in your future laptops

Okay, with that out of the way, let’s talk about the issues I had with my T440. My biggest complaint was the screen. It was a TN panel (a bad one in that), which has dull colors and bad viewing angles (as compared to an IPS). There was also only one RAM slot maxing out at 8GB, and I had the version with no soldered RAM. I missed the ability to expand the memory at times.

Then there was the trackpad, which I later learned was nothing like Thinkpad trackpads, and this had to be upgraded too. I could’ve done the upgrades, but I preferred going for a new laptop as it wasn’t much of an overhead in terms of price (factoring in T440’s resale value) and I was eyeing an X230 for some time now.

What I really liked about the T440?

Snap from my other article

I absolutely loved how sturdy and rugged the laptop was. No flex in the keyboard or the screen whatsoever. My previous laptop, Fujitsu Lifebook A514, had to retire because of this exact problem. The keyboard was a joy to type on, and while I later learned that this keyboard was a step back for many from the classical Thinkpad keyboard, I’d any day prefer the new Thinkpad’s keyboard over my Macbook Pro’s or Fujitsu Lifebook’s.

In closing

Overall I’m very happy with my new X230. It seems like a laptop I could use for some years, hopefully without many issues. I’m also happy that I’m back to running GNU/Linux as my daily driver! Reach out to me if you are planning on going this route and have questions.

Cheers, thank you for reading.

Coronavirus Gratitude

I distinctly remember the last week of February. A bunch of my colleagues and I got together at a Chinese restaurant to have nice food. The next day was Saturday and I went running at Tempelhofer Feld. Sunday was relaxing at home all day except for a little Coffee trip to Alex.

Like for many people, the threat of Coronavirus was downplayed by the fact that it seemed way too far away. Until suddenly it wasn’t. We hurried home on the first Monday of this month halfway through the day, and that marked the beginning of self quarantine for me. More a month later, here I am writing this article after having embraced this new way of life in self quarantine; social distancing, self isolation and working from home culture.

So I’m sure most of you reading this in the near future or even the distant future know and understand the gravity of the current situation, and even if you don’t, there are great sources out there that you can use to make and keep yourself informed. We’re not going to talk about any of that in this article. What I’ll instead like to write about is all the things in life that I took for granted that I should’ve been grateful for. If there’s something positive about this whole situation, it is that it reminds us how lucky many of us are living in comforts of our social security, freedom of movement, privilege to eat and hangout in the sun. To make sure I don’t forget the lessons from this time, I’ll make a note of some of these privileges in this article.

Freedom to travel

For me, the only restriction of movement I ever felt was either bureaucratic, like requirement of visa, or monetary, like needing to save money to visit some place. I grew very introverted and most of my time would get spent at home, but that was a choice. I never had to experience what a lockdown feels like. Now, I feel like many people like myself can relate more, and hence, empathize with the struggles of communities living under lockdown, not because of a virus but geopolitical instability.

Meeting friends and colleagues at work

Having the option to socialise is very underrated. In fact, having to meet people in real life is sometimes frowned upon. We tend to make jokes about how meetings at workplaces suck, and how we’d rather work in solitary for all our lives if we could. While there’s certainly some truth to the notion of reducing unnecessary meetings, I think workplaces can be a great place to meet people of different kinds, find friends and work on your soft skills. There’s also that extra joy of forming little groups to go to fancy lunches.

Biking on a super fine day

I love my bike. And when the day is nice and sunny, there’s nothing better than riding the bike in a random direction for a while, parking next to a Coffee shop, grabbing a Coffee, hanging out at the flea markets and more! Aah, those days. It is especially painful writing this because today is almost one such day.

Hangout at the supermarkets

For me, grocery shopping has become something that I look forward to. I find it quite entertaining to go to supermarkets and ponder over all the variety of goods they have there. It is probably also because German supermarkets are sort of new to me, coming from a convenience store culture, I get mesmerized by all these huge supermarket chains they have here (not to mention the differences in cuisines between Germans and Indians). Can’t wait to get back to that routine!

Hangout at friends’ places

I often go to my friends’ places, and they sometimes come over to mine. It is always nice meeting people over the weekend, playing a board game or cooking, or simply chatting through the evening. It recharges you for the next week and during the week there’s always something one can look forward to if things aren’t the smoothest!

Shawarma, Kabap, Döner, Kofte

For me, all of these are my guilty pleasures and I can’t wait to get back to them. In Berlin, no matter what, you have a Döner joint right around the corner and for many, life’s just not the same without a regular Döner meal.

They take Döners very seriously in Berlin

The feeling of control

On slightly more abstract terms, I miss the feeling of control we generally have, or think we have, in life. We plan vacations months in advance, not worrying about flights being grounded or international borders closed. The recent timeline of events makes one realize how fragile things are, and man made structures do a good job of, even if momentarily, giving an illusion of full control and predictability.

In closing

I hope you are doing well wherever you are. If you work in an essential services industry and still go to work, I applaud your efforts and your courage. If you are sitting at home waiting for times to get back to normal, I think it helps to document or simply reflect on exactly what you’re looking forward to so that when things actually go back to normal and you do your everyday activities like going to work, eating good food at a restaurant or visiting a friend, you would be reminded how special each one of those activities are.

Stay healthy and safe, and thank you for reading!

What Writing A Web Development Tutorial Taught Me

I recently wrote a tutorial on getting started with web development. It was a frontend only (meaning covering only HTML, CSS and JavaScript), 5 day tutorial that covered very basic web development topics and concepts like HTML elements, CSS selectors and JavaScript language semantics. Along with learning the basics of frontend web development, the course takers built their very first website which was a simple, one page portfolio site listing their interests and some pictures.

I’d not go into the technicalities of the course itself, as that’s off topic. What I’d like to do in the little post is list down some things I learned while I was writing the course, about writing the course and also about writing your thoughts down in general.

  1. If you’d like to test your understanding, try explaining it
  2. Many obviously true beliefs that you hold probably aren’t true
  3. Explaining is an art
  4. The role of an editor
  5. Writing requires a lot more focus than programming
  6. Having a continuous thought train for a multipart article is exponentially more difficult than writing a one off article
  7. Have a plan or outline
  8. Know your audience’s technnical competence

So, without further ado, let’s get started.

If you’d like to test your understanding, try explaining it

“The person who says he knows what he thinks but cannot express it usually does not know what he thinks.”
— Mortimer Adler

The above quote from this interesting blog post about Feynman Technique on Farnam Street captures the gist of this learning. We’re good at convincing ourselves that we understand something when in reality we might not. It is similar to when we speak a language natively and are confident in our knowledge, but then when a language-learner asks us a simple question, we don’t have an explanation but rather know it ‘intuitively’.

As an example, when I was writing the chapter on JavaScript, I was tempted to write that arrow functions have replaced the ‘function()’ functions. I asked myself why I thought that was the case, and I didn’t have an answer. I had just ‘believed’ that to be the case.

Upon researching, I learned the differences in their workings and their use cases, and I came out of that a bit wiser than before. That was just one instance where I wrote something, then asked myself why I thought that was the case, and learned that that was in fact not the case.

The bottom line here is, if you want to learn something well or test your understanding, try explaining it. Interestingly, that’s just me rediscovering the Feynman technique.

Many obviously true beliefs that you hold probably aren’t true

This is an extension of the previous point. But with a different takeaway. Since we’ve now established that many of our beliefs are wrong, it is wise to not be too confident in them and always practice humility when it comes to your knowledge, and consequently, your opinions and worldview. In other words, while it is great to put in time and energy to learn something properly and have opinions about it, it is also important to be ready to accept that you could be wrong and change.

This point is best illustrated by the “Strong Opinions, Weakly Held” philosophy, best outlined by a little paragraphy from this post.

A couple years ago, I was talking the Institute’s Bob Johansen about wisdom, and he explained that – to deal with an uncertain future and still move forward – they advise people to have “strong opinions, which are weakly held.” They’ve been giving this advice for years, and I understand that it was first developed by Instituite Director Paul Saffo. Bob explained that weak opinions are problematic because people aren’t inspired to develop the best arguments possible for them, or to put forth the energy required to test them. Bob explained that it was just as important, however, to not be too attached to what you believe because, otherwise, it undermines your ability to “see” and “hear” evidence that clashes with your opinions. This is what psychologists sometimes call the problem of “confirmation bias.”

While you’re at it, I recommend reading this article by Jeff Atwood where I first read it. There’s also this nice TED talk along the same lines.

Explaining is an art

It is not easy to explain why linear-gradient works the way it does. It is hard to explain parameters of a function to someone who has never written any code, and you cannot use words like parameters, arguments or function call before explaining them. In short, writing a beginners programming course is some work (who would’ve thought?!). Now I look back at all those books, articles and tutorials that taught me the basics of everything I’ve learned and realize how great it was to have had all of that top quality learning material for free on the internet.

My personal experience is that we don’t notice when something is very well written or explained, especially with technical writing and documentation. It feels very natural and in-flow. But try to remember the last badly written article that you read. It was exhausting, you had to re-read through paragraphs to make sense of the text and you probably didn’t even finish it. That’s why, the next time you read through something and don’t notice anything wrong, take a moment to appreciate the effort that might’ve gone into making it come across the way it does.

The role of an editor

I learned what an editor does while writing this course. I would typically submit a day’s work as a document, fairly confident that I had done a good job only to find out the next day that the document has 200 new comments and edits. How was that even possible? I’m not a good writer, accepted, but those many edits? I would genuinely fear submitting my work for editing, just like my younger self would fear exams for all the bad grades I could get.

But in this case, the editor is really there to make the text readable, check if the sentences flow naturally and there’s no discontinuation of thoughts (and of course, spelling and grammatical shortcomings in the text). All in all, after the edit the content doesn’t look anything like the initial draft I sent for editing. If you ever get the chance to get your work reviewed by an editor, don’t miss it. You’ll learn a lot.

Writing, for me, requires a lot more focus than programming

I realized how much more focus writing content needed as compared to programming. I could just not do it in the office. Every 15 minutes I’d lose my train of thoughts due to some or the other distraction. I believe this could be just because I’m not used to the idea of writing content in the office, or writing professionally in general. I would end up taking work from home days to make sure I’m making progress. I had not expected this to happen, especially after having been an amaeteur blogger for a while now. But there I was, trying to think of the next sentence while repeatedly reading the paragraphs above.

Having a continuous thought train for a multipart article is a lot more difficult than writing a one off article

So I feel quite comfortable writing something like this very post. It is not as long, and one can write the whole thing in a couple of sittings. Then there are also not a lot of different ways of presenting here. Just text followed by headings followed by more text. That’s quite a lot easier than writing a multi-day course with each day three or four times as long as a typical blog post with many screenshots, git commits, code snippets and, of course, text. It is important to keep track of all your resources, and any mistake you find later on means all the screenshots and git commits from that point on needs to be updated, which is quite a hassle.

Have a plan or outline

To avoid finding technical faults / discontinuities in the text much later in the course writing, having a plan or an outline about the content is very important. Each chapter, and every topic in the chapter should be outlined before even starting with the actual writing. Ideally, even the outline should be reviewed by someone who knows about how learning works (yes, that’s an expertise), and the final outcome should be communicated well in advance. You want to avoid making the course too difficult (and have people drop out after getting stuck) and too easy (and have people drop out after getting bored).

Know your audience’s technnical competence

When you’re writing a beginner course in software development, you have to explain every bit of technicality. From creation of a file with special extension to what a git commit is. Any assumption you make regarding the ability of the user to understand the course’s substance can backfire resulting in many course takers abandoning the course mid way or flooding the communication channels with their questions. To avoid this, it is important to know the technical competence of your target audience. You cannot cater to a wide range of expertise, and no matter what you write, many people are going to be left out. But that’s okay.

In closing

I’m glad I found this opportunity to do some professional writing. I learned some important aspects of writing, and I tried to share my experiences with you through this post. I hope you find something useful out of this. As always, thank you for reading!

Elementary Theme For Jekyll

It is hardly ever the case that I work on a single side project for years, a sentiment that my fellow software developers might share with me. This blog that you’re reading this article on is one such rare project. And although there have been crests and troughs in terms of my activity here, it has been fairly consistent, especially considering my reputation of abandoning projects.

Anyway. Where I was going with all that blabber was that this template that you’re reading this on is already two years old now, and I recently rolled out an update that I was pretty proud of. In this little post, I’d like to outline in brief how I reached the current version of this template and why I’m super happy with the outcome.

Backstory

I created the template by simply removing as many unnecessary parts of my then current template as possible and making it a simple, one request only template. It was essentially a blank HTML page with few lines of CSS, no JavaScript, default browser font and styles. Of course, it was blazingly fast but also quite ugly. I went to the extreme end of the spectrum as my starting point.

Slowly, I added stuff to it, on a strictly per-requirement basis. More CSS, some JavaScript, introduced SCSS to make the CSS maintainable, made the JavaScript optional as not everyone needs a dark mode and so on. I made the project installable via git submodule so that it is easy to customize it and at the same time pull updates from upstream.

Current status

It feels good to not trigger advertisement and tracker blocking tools like uBlock Origin. And by not loading hundreds of kilobytes of minified code that contains trackers, suboptimized routines and who knows what, I’m also being fair to my visitors who, when you think about it, trust you as the web developer by loading and executing your code on their machines.

On a more objective side of things, here are a couple of features (copied over from the project’s github readme) I’m super happy to announce:

  • Lightweight, <10KB CSS, <3KB (optional) JavaScript + 15KB Open Sans font file + your content. That's less than 40KB transferred for most pages
  • Highly accessible with semantic HTML
  • Structured data (schema.org) pre-added for blog posts
  • Dark mode (requires JavaScript for toggling class and saving user preference in cookies)
  • Reading progress slider on top (requires JavaScript)
  • JavaScript is optional (turn it off in _config.yml)
  • No request made to any third party
  • Installable as a git submodule

Try the project here: https://elementary-jekyll.github.io/. Below is a picture collage of interesting observations about the theme.


Picture showing 100 score on Google Page Speed, <1 second median load time, 100% cached on Cloudflare and a screenshot of the template running on Kindle
Picture showing 100 score on Google Page Speed, <1 second median load time, 100% cached on Cloudflare and a screenshot of the template running on Kindle. Mobile users can click on the image.

Here’s what the dark mode toggle looks like.

Dark mode demonstration

And this is the scroll progress indicator

Reading time indicator

Todo and future

I’m probably not going to give up on this template just yet. But I really want to move away from Jekyll now. No, I don’t dislike it. It is probably perfect if you just want to focus on writing as a person who doesn’t mind using text editors and the terminal. I just want to be able to dig into the source code of the build tool, the configuration files, write a plugin myself, be more comfortable with the whole ecosystem in general. To do that, it is important that I move to a tool that’s written in a language I know, or want to learn. Jekyll, and hence Ruby, just isn’t either of those.

If you’re thinking of starting a blog, or moving to a new template and see this one a good fit for your taste, do give it a shot. In case you actually end up using it, please write to me. Of course, it is open source and GPLv3 licensed. In the future, if I manage to move my blog elsewhere, I’ll port this template to the new system.

I remember wanting to have a simple static site generator after having struggled with tools like WordPress and Blogspot for this blog. I’ve reached a point where I feel like I need some of that complexity back. Guess I’ve reached the other side of the sine curve!

Thank you for reading.

Clean Code – Quotes

Listing down some interesting quotes I read in Clean Code by Robert Martin. To quote him, reading these things would only serve as a feel good exercise without the actual meat of his methods. Nevertheless, I felt they’re too good to not make it to my blog. Enjoy!

Nonsense! We will never be rid of code, because code represents the details of the requirements. At some level those details cannot be ignored or abstracted; they have to be specified. And specifying requirements in such detail that a machine can execute them is programming. Such a specification is code.

Of course you have been impeded by bad code. So then—why did you write it? Were you trying to go fast? Were you in a rush? Probably so. Perhaps you felt that you didn’t have time to do a good job; that your boss would be angry with you if you took the time to clean up your code. Perhaps you were just tired of working on this program and wanted it to be over. Or maybe you looked at the backlog of other stuff that you had promised to get done and realized that you needed to slam this module together so you could move on to the next. We’ve all done it.

They may defend the schedule and requirements with passion; but that’s their job. It’s your job to defend the code with equal passion. To drive this point home, what if you were a doctor and had a patient who demanded that you stop all the silly hand-washing in preparation for surgery because it was taking too much time?2 Clearly the patient is the boss; and yet the doctor should absolutely refuse to comply. Why? Because the doctor knows more than the patient about the risks of disease and infection. It would be unprofessional (never mind criminal) for the doctor to comply with the patient. So too it is unprofessional for programmers to bend to the will of managers who don’t understand the risks of making messes. The Primal Conundrum Programmers face a conundrum of basic values.

Clean code always looks like it was written by someone who cares. There is nothing obvious that you can do to make it better. All of those things were thought about by the code’s author, and if you try to imagine improvements, you’re led back to where you are, sitting in appreciation of the code someone left for you—code left by someone who cares deeply about the craft.

Will update from time to time…

Thank you for reading!