Table of Contents
We already have a lot of bookmarking services, so why bother writing another one? Good question.
In short, I want my bookmarking service:
- To be very quick to use;
- To provide a way to organize my bookmarks in a powerful way.
I tried a lot of existing bookmarking services, and I wasn't satisfied by any of them, for a variety of reasons.
Let me elaborate on the organization part first. The simplest way to organize bookmarks is to introduce folders to group them. This still poses a well-known problem though: some bookmarks can logically belong to multiple folders. In order to address this issue, some services use tags: now we can tag a bookmark with more than one tag. So far so good.
Now, assume I have a generic tag
programming, and a couple of more specific tags:
c. I definitely want my bookmarking service to be smart enough to figure that if I tag some article with either
c, it means
programming as well; I don't want to add the tag
programming manually every single time. So, what we need is a hierarchy of tags. Surprisingly enough, I failed to find a service which would support that.
This hierarchical tags thing was a major motivation for me to start Geekmarks.
Another important thing is that I want bookmarking service to be very quick to use. I don't want to go through these heavy user interfaces and look at all the eye candy. In my daily life I just want to either add a bookmark or find one, and I want to do that quickly: like, just a few keystrokes, and I'm done.
And last but not least, I love open-source. So, meet Geekmarks! A free, open-source, API-driven bookmarking service.
There's a backend (written in Go and PostgreSQL) which exposes a RESTful API, and various clients which talk to the backend.
All the data is stored on the server; client does not store anything. Even when the user enters a tag name, and UI shows the autocomplete menu with matching tags, the menu contents are loaded from the server.
Of course, this has both advantages and disadvantages.
The good thing is that the arcitecthure is “clean”: clients are dumb, server is the one who does all the job. Among other things, this simplifies the process of writing new clients, and all the data is automatically synchronized between all user's clients with no extra effort.
Now let me consider disadvantages and argue why I still opted to use this design.
- Some users might have a strong opinion against storing their bookmarks (as well as any other data) on a third-party server; they want to control the data storage. This part is solved by the fact that everything in Geekmarks is open-source: one can easily deploy the backend to their own server, or even run it locally on the laptop; and adjust the backend URL in the client settings. Now, everything is under the user's control.
- Other users might be fine with storing bookmarks on a third-party sever, but they might be afraid of losing all their data if the service stops working for whatever reason. In order to address this issue, I'm going to implement import/export of all the account's data. So, one might write a short script with a single
curlcommand which fetches JSON data with all tags and bookmarks and saves it locally, and run this script regularly (via crontab or similar things). Now, the data is backed up, and if something bad happens with the server, the user can resort to deploying Geekmarks backend to their own server or locally, and import all the data there.
- One more possible claim is that the tool won't work offline. While this is true, it shouldn't be a major concern, because the whole point of Geekmarks is to store URLs, so even if you can get the previously saved URL offline, you'll anyway need the Internet connection in order to visit the webpage by this URL!
- And the last thing I can think of is that constantly accessing the server for this and that is slower than just storing everything locally. Of course it is slower, but it doesn't affect user experience too much: all the communication is going via the websocket, and, from my experience, the user rarely needs to wait more than 150ms (for me, it's usually less than 70ms actually).
Backend is thoroughly tested and is very stable. API will be also frozen soon.
Client implementation, however, is not in a particularly good shape: it's a Chrome extension, and it's only a proof of concept. It's just barely good enough: it provides all the features and it's completely usable, but it's written in probably not a very good manner, its appearance is kinda rough, etc.
My plan is to rewrite the client in Angular 2, or maybe React, and hopefully I'll be able to factor out the most part and reuse it for many kinds of clients: web interface, browser extensions, and mobile phone apps (via Native Script or React Native). But that will be a long story, since I'm not really a frontend guy, and I'll need to learn a lot.
After installing the Chrome extension, click on the “g” icon:
Log in (via Google account), and when it's done, menu will look as follows:
Now, on any page you want to bookmark, click “Create bookmark” from the menu (or use a hotkey; I personally use Shift+Ctrl+B), enter tags for your new bookmark, and save it. Tags which don't yet exist will be created on the fly.
When you do that for the first time, it might look as follows:
Later, when you have more tags, the process of adding a new bookmark will be faster, like this:
And this is how you find your bookmarks, after all (I use a Ctrl+B hotkey for that):
Being able to organize bookmarks with hierarchical tags is really nice, but sometimes I'm too busy and I don't want to think carefully about where to put my bookmark; instead, I just want to quickly add it somewhere, and postpone the proper tagging for later. This is supported: when one wants to add current page as an untagged bookmark, it's as easy as
Enter (provided that the keyboard shortcut is
Next time, when “Find bookmark” dialog is opened, all untagged bookmarks are shown immediately, before the user enters any tag; so, the user won't forget to tag them properly later.
When editing a tag, one can specify multiple comma-separated names, and all of them will refer to the same tag. It's convenient in many cases, e.g.
Note on hierarchical tags
I really love the hierarchical tags idea, and as I said, it was a major motivation for me to start Geekmarks. However, one should not misuse it.
For example, it's perfectly fine to place
programming, because Go, indeed, always implies programming.
But consider the case when we want to store something about terminal emulators, and we want to be more specific: terminal emulators which work under Linux. It would be a bad idea to create a hierarchy like
linux, of course, does not necessarily imply
terminal. If we go with this, then we'll eventually end up with a bunch of tags like
/whatever-else/linux; and when we type
linux in the tags input field, we'll get multiple tags with the same name, and we won't be able to just get “everything related to Linux”.
/linux should be a standalone tag, and the URL which describes something about terminal emulator under Linux should be tagged with both
So, the rule of thumb is: before placing a tag
bar, ask yourself: does
foo always imply
bar? If yes, then go on. If no, then
foo should be a separate tag.
That said, if you're unsure about how to arrange your tags, don't worry too much about it, since you can easily move your tags around later, and your bookmarks will be retagged appropriately.
I don't really know when I'll be able to implement all of it, but nevertheless, this is what I'd like to have sooner or later:
- Firefox extension;
- Client for Android (and probably iOS);
- Authentication via something other than Google;
- Filter bookmarks not only by tags, but also by title/url;
- Export/Import of all the account's data;
- Add numeric “rating” to tags, and sort bookmarks accordingly to the rating of the tags it's tagged with.