This is going to be my second year running Simple OKR. The beginning of a new
year is usually the time when I start collecting all business income and
expense data and start filing various LLC paperwork with the state.
I thought I’ll share how much I made this year from Simple OKR.
It’s only ~15K USD in annual revenue. Of course I’ll have to pay ~25% in taxes
on that grand total number, which will probably gonna bring me down to ~10K USD
in profit. The ARR is about 10% increase from the previous year. It’s a
positive change, but has very little meaningful impact on my life.
It’s really hard to launch a successful SaaS on your own. I’m kinda surprised
that I’m making any revenue at all. I’ve been building Simple OKR as a
“side-project” for over 2 years. I remember quitting my full-time job in
mid-2019 when I started seeing steady increase in MRR (~1.3K) and I thought I
should focus on it full-time. Unfortunately, after I quit my job, the MRR
started going down (to ~600 USD) and I did not bring in any new customers for
about 3-4 months. That was a really depressing time for me and I decided go
back to work full-time elsewhere. Looking back at this, I probably made the
right choice to get a job. I tried to move too fast and burned.
Hmm, my major mistakes… I think there are several things I can think off.
First off, technology choice. Simple OKR is built in Go and React JS. It did
not start like this. It went from simple server side rendered app to React JS
frontend. I’m fairly happy with Go as a programming language, but I think I
should have stayed with SSR instead bringing in React. Bringing in react just
meant that I had to build out an API (complexity++) that can be used with
React. It does not make HTML or CSS parts that much simpler or easier to reason
about. I was still able to make a fairly big mess out of React components (complexity++).
Second issue… UI redesign 3x. I redesigned the UI of Simple OKR probably 2 or
3 times. Of course, the goal was to improve user experience and make Simple OKR
for people easier to use and reason about. I’m not sure I was successful in
achieving that. You can see it’s still clunky and difficult to use (waistedTime++).
Third mistake was to try and add another product to the main offering. Let me
explain. I started building out a new product to complement Simple OKR –
Performance Reviews. The goal was to bring performance reviews from your
manager and peers and tie those back to OKRs somehow. I wasted about 2 months
on this and did not see much interest (waistedTime++). I still think it’s a
good offering, but only when the time is right.
I think these are probably the three big mistakes that come to mind. Mostly,
all of them revolve around wasted effort on stuff that does move the needle.
Not everything was that bad. On the good side, running ads early on was
a great decision. When you bring something new to the market, nobody knows you.
You need to have distribution channel for your software so it gets discovered.
Google ads was that channel for me. I still pay ~80USD/month for google ads just to
maintain the foot traffic. Though, it’s not very sustainable approach unless
you have tons of cash to burn. Though, I think without buying ads I probably
wouldn’t have gotten to the current MRR at all.
At the moment I’m not entirely sure what I want to do with Simple OKR. Should I
continue cleaning it up and making it better. Or should I just leave it and let
it die on it’s own. I know there’s still lots of potential for this product.
For the past few weeks I’ve been working on a new personal project. I want to
build an experimentation platform that lets you easily setup and run various
experiments on the web. One key component of this project is to be able to
encode experiment configuration as data instead of implementing all the rules
in code. Having configuration in data makes it easier to change and update
experiments on the fly without having to rebuild the app.
I started developing Brogue parser and evaluator. Brogue as in accent, not the
shoe. Brogue expression syntax is based on the idea of Lisp’s
S-Expressions. However, it’s
encoded as JSON object (so it can be more easily parsed and understood by the
frontend code if needed). Let’s look at this example:
Example above is a valid Brogue expression. Once evaluated it will return
either “Sign up for 14-day trial” or “Start free trial now”. The example above
uses 3 functions: if, lt and hashmod. In this example, hashmod takes a hash of
value “user-1” and mods it by 100. Then passes it to the lt function which
checks if the mod is less than 10 or not. If it is smaller than 10, we will
return 14-day trial message, otherwise we will get “Start free trial now” back.
Where this gets really interesting is that you can actually supply external
information when evaluating the expression.
This example is actually equivalent to the first one. It will produce the same
result. However, now the user id is passed from some external source instead of
being hardcoded in the rules. This open up lots possibilities for constructing
complex rules that produce different results once the operating context
changes. Brogue is also extensible. I am able to add new expressions very
easily by implementing a Go function and binding it to some function name such
At the moment Brogue is implemented in Go and is still in the works. I may open
it up once it’s complete and I have more concrete cases.
FreeBSD installation images come with “Live CD” option. If you choose it, the
installation image will boot in live cd mode. This is really useful if you want
to explore core system from the command line or do some fixes on already
If you want to install more applications to have a better test drive you’ll be
in trouble because root file system is mounted as read-only. The root file
system also takes up 100% of space due to how installation image is setup
leaving you no room to add new software.
There’s a very simple workaround that lets you put FreeBSD live cd into
writable configuration. Boot up into usb image and enter live cd. Then run
mount -uw /
# edit (vi) /etc/fstab and change ro to rw
Reboot the system when you’re done. When you boot it up next time, your root
will be writable and will expand to the remaining free size of your USB stick.
Clipboard in Linux was always a PITA as far as I can remember. We have three
clipboards to work with in X11: primary, secondary and clipboard. Primary
buffer is typically used in terminal apps (e.g. when selecting text with
mouse), secondary not sure, and the “clipboard” is used by GUI applications such
as you web browser and such.
These clipboards are not automatically synced by default. For example, if you
select console text and try to paste it in your browser it won’t work out of
the box. You can transfer primary buffer context to clipboard with xclip like
xclip -o | xclip -selection c
Then it will work. But who wants to do this allthe time.
There’s a program called autocutsel that can help you with clipboard
sync. You just need to install it and add the following to ~/.xinitrc:
if [ -x /usr/bin/autocutsel ]; then
# keep clipboard in sync with primary buffer
autocutsel -selection CLIPBOARD -fork
# keep primary buffer in sync with clipboard
autocutsel -selection PRIMARY -fork
It will start autocutsel in the background when X starts and keep clipboards
After I decided to get back into blogging and hosting my own site I started
looking for the right approach and tools for creating my site and blog.
Instead of picking up an existing blogging platform (such as Wordpress) or some
static site generated (e.g. Hugo) I decided to roll my own tool for building
this site. Some people probably think that I’m crazy for doing that, but I
think it’s the right choice; at least for now. Here’s why.
There’s a steep learning curve to any new platform that you want to start
using. I’m not proficient in Wordpress, plus it adds more complexity to
hosting (I need a DB). Same holds true for static site generators. I previously
used Hugo, it’s great, but again there’s a learning curve and I need to adapt
myself to their approach of doing things.
I decided to roll my own solution. I wrote a simple static site generator in
Go (as of this writing it’s implemented in under 200 LOC). I
take markdown files, convert them to html and produce this site. It’s really
simple. The nicest thing is that I have full control over all aspects of site
generation. I don’t need to learn how to use some existing tools, I already
know Go and that’s all I need. We’ll see if I’m going to regret this approach
or not, but so far it seem much superior to anything I used before due to its
simplicity and flexibility.
I’m an avid Linux user and I’ve used Linux for probably over a decade in some
capacity either at home or professionally.
At the end of 2018 I got myself a new desktop computer and decided to make
Linux my primary driver at home. I mostly do development work on a computer
anyway, so it lends itself very good to that. I decided to install Arch Linux
since this is what I used many years ago and I like its minimalistic nature and
up to date packages.
Unfortunately, over the past couple of years I kept experiencing kernel
crashes. It’s still unclear to me why I’m getting these system crashes.
Initially I thought they were related to hardware being “too new”. However, I
still experience the same crashes two years and many kernel upgrades later. The
crashes don’t happen often, but I noticed that I typically get them during
systemd upgrades. If I get a crash during systemd upgrade it will most likely
leave the system in a bad state, requiring me to manually interfere and fix
things from a bootable USB. This is really bad because now I’m hesitant to
perform system upgrades.
Here’s some lspci output for the reference:
00:00.0 Host bridge: Intel Corporation 8th/9th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S] (rev 0a)
00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 630 (Desktop 9 Series)
00:14.0 USB controller: Intel Corporation Cannon Lake PCH USB 3.1 xHCI Host Controller (rev 10)
00:14.2 RAM memory: Intel Corporation Cannon Lake PCH Shared SRAM (rev 10)
00:14.3 Network controller: Intel Corporation Wireless-AC 9560 [Jefferson Peak] (rev 10)
00:16.0 Communication controller: Intel Corporation Cannon Lake PCH HECI Controller (rev 10)
00:17.0 SATA controller: Intel Corporation Cannon Lake PCH SATA AHCI Controller (rev 10)
00:1b.0 PCI bridge: Intel Corporation Cannon Lake PCH PCI Express Root Port #17 (rev f0)
00:1c.0 PCI bridge: Intel Corporation Cannon Lake PCH PCI Express Root Port #1 (rev f0)
00:1d.0 PCI bridge: Intel Corporation Cannon Lake PCH PCI Express Root Port #9 (rev f0)
00:1f.0 ISA bridge: Intel Corporation Z390 Chipset LPC/eSPI Controller (rev 10)
00:1f.3 Audio device: Intel Corporation Cannon Lake PCH cAVS (rev 10)
00:1f.4 SMBus: Intel Corporation Cannon Lake PCH SMBus Controller (rev 10)
00:1f.5 Serial bus controller [0c80]: Intel Corporation Cannon Lake PCH SPI Controller (rev 10)
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (7) I219-V (rev 10)
03:00.0 Non-Volatile memory controller: Micron/Crucial Technology P1 NVMe PCIe SSD (rev 03)
My CPU is Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz.
Recently I’ve been contemplating switching to FreeBSD. I’m hoping to get more
stability from the system at the expense of losing certain software (though I
don’t need much). My biggest blocker at the moment is the lack of Docker for
FreeBSD. It’s something I need for certain dev workflows and publishing my own
software to GCP. Though, I wonder if I should be able to get around it with
bhyve and VMs for docker where I need to build images.
When to build it from scratch from a business perspective? This is a complex
question, but I’m going to give you a simple answer.
In an ideal world, with unlimited time and resources, you should always build
your own software. This will give you full control over features and life-cycle
of the software.
Now, of course the reality is that we don’t have unlimited resources. Then, we
should build software that’s core to our business. Don’t waste time on
implementing low level libraries and frameworks if that’s not core of your
Over the past decade in software engineering I learned that you want to start
by owning the core of your business with the intention to replace the rest of
the software with in house solutions. Off the shelf solutions are great
initially since they give you speed and a way to test things out, but at the
end you will always want more control, which can only be achieved by owning the
software completely. Very few businesses will end up there.
Own what’s core to your business with the intention to own everything
What is writing about? Why do people share things online and blog? It is much
easier to answer this question when one has picked a theme they want to write
about. If you would like to focus on technology and gadgets, then it’s easy to
say that you’re writing because you want to discover and share interesting
things about the latest technology. That could be one example.
For me it’s a bit different. I don’t really have a clear theme, goal, or topics
that I want to explore. I think personal blogs should not have themes at all.
Themes are great to focus your efforts in order to produce quality blogs that
cover certain topics, but at the same time they limit you and your ability to
express whatever is on your mind. The freedom to express yourself is essential
to creating a long lasting personal blog. The ideas, beliefs, interests and
many other things change over time which also means that the theme of your blog
should also evolve.
OK, so what and why this blog? This is going to be my 3rd (?) attempt at a
personal blog. I don’t want to pick a specific theme or topic. Previously I
tried focusing on tech and engineering. This time I’m planning to write about
whatever I find interesting without being bound to any topics or themes. It
will probably lean toward tech topics, but time will tell. I doing this because
I think I need to have some personal space online.