Essays by Paul Graham

Almost three years ago, I was deciding on my next read and decided to read all of the then-existing essays by Paul Graham. Luckily, I found a GitHub project that converts all of the essays into ePub format, compiling them into a book. Over the last couple of years, I’ve been slowly reading the book, and for the last couple of months I’ve been dragging my feet, since I didn’t really want to finish it – which I sometimes do regardless.

Well, it is finally over, and while Paul has posted new essays, I think I can call it done regardless, since otherwise the book would be endless. I guess that’s the difference between posting essays online and having a book with hard boundaries. In any case, I think I’m ready to pass judgment.

It is quite marvellous to see earlier posts and some predictions that didn’t come to fruition – Java is a major programming language under active development and not an “evolutionary dead end.” However, it’s not an indication of anything other than that Paul is human and doesn’t seem to have a crystal ball. He does, however, have a sharp mind and writes quite well. While I personally don’t always agree with his takes on certain things, I did wish I had read his essays 25 years earlier. Even though I wonder whether I would have understood and embodied some of his ideas. All that makes me wonder if he should do some kind of book for youngsters.

As I was trying to encapsulate Paul’s writing, I couldn’t help but think of How to Solve It by George Pólya and Maverick by Ricardo Semler. As a matter of fact, I think prior to reading Paul’s essays, it is worthwhile to read How to Solve It. I feel like it would make a reader appreciate and enjoy the essays even more. While Paul focuses on his entrepreneurial experience, those ideas are also quite useful, and reading all the essays makes you feel like you can put together life’s puzzle, even if you are far too late to the table.

I personally do appreciate such candor – no smoking mirrors or BS – but one thing that slightly bothers me is the lack of essays on the topic of failure. While Paul did address the idea of “if I didn’t do a startup…” in one essay, laying out plainly the course of action he would take with regard to making a living (finding a low-risk, safe job), I still feel curious about tons of startups that didn’t make it. Startup failed, now what? My guess is it is similar to evolution: if you didn’t survive and reproduce, then you end up on an evolutionary dead end, but less dramatic, since the failure of a startup is not the end of a person.

So, should everyone read Paul’s essays? I don’t know. The crux is that as you read his well-thought-out ideas, you might change your perspective, get ideas, even if it is too late for you to put all your chips on the table and give it a chance. His thoughts make you think and wonder. To me, it is worth something; to others, I don’t know.

P.S. I attached unedited notes with a couple of not-very-thought-out arguments and a ton of interesting cutouts from Paul’s essays.

In a nutshell
+: Well-thought-out essays; interesting to follow over the years, as things change.

+: Various topics, with a focus on startups.

+: The author is human: sometimes he is right, sometimes wrong. Take it for what it is.

+/-: Not a book; don’t expect chapters, continuity, or a guide on a subject.

-: Sometimes the author drums up startups too much; it feels like adverts rather than an objective take.

=: You will get something out of it, but it is rather up to you how much you want to pull out, how many ideas you want to entertain and consider. If you value the thinking process, it will be worthwhile.

Title: Essays

Author: Paul Graham

Cover: None

Day Trip – Dayton, OH

While I don’t have much interest in aviation, I had wanted to see the National Museum of the U.S. Air Force for a while, but it never seemed to be a good time. Well, this year I figured it was time to catch up.

Short prep on Friday evening: water, soda, snacks, sandwiches, and a cooler; take off Saturday morning at 7:00. It is a short three-hour drive to Dayton, and we started at the Wright Brothers museum – a good place to appreciate where it all started and what was to come. The Wright brothers first flew on December 17, 1903, and the first moon landing took place on July 20, 1969 – that is a stunning 65 years between. Just think about that for a moment: in one lifetime, humanity went from learning to fly to traveling beyond Earth. Truly stunning.

The National Museum of the U.S. Air Force is huge, and by all rights it deserves several hours by itself. Luckily, I had family with me whose enthusiasm evaporated sometime between the first and second hangar. So, we – as a team – managed to cover the entire museum in a couple of hours. Once again, it is stunning to see basic wooden airplanes with multiple wings and engines mounted on top, only to realize that in a short 36 years, jet airplanes started to fly. While I managed to see all four hangars, the gift shop was cut short when a fire alarm sounded and the entire museum got evacuated.


We wanted to go see 2nd Street Market, but it was too late and it was closing. So were the Dayton Art Institute and Carillon Historical Park. That’s the catch with day trips: Saturday is the only day, and there are no long hours. But there was one more place that was open and I wanted to visit – Buc-ee’s.

I’ve been to a few gas stations in North America, and typically it is not a destination you are looking forward to. Not Buc-ee’s. It was something different. In my case, the dead giveaway was people hanging out in the parking lot, lawn chairs out, and a really clean area outside and inside. Yes, the sandwiches are good, the shop is entertaining – and feels a bit overpriced on some items – but the atmosphere is friendly and inviting. And while it is crazy busy, it is somehow relaxing. It is surprising how someone managed to make a gas station into a destination, but they did, and I would visit it again.

Day Tripping – Holland

I don’t tend to write about day trips, since they are short and, well, how much can you really get out of them? Well, I guess more than staying at home and working on a never-ending list of things to do! While there is nothing wrong with catching up on homework and projects, at some point it is worth getting out and getting a healthy dose of a different perspective. And while grand tours provide a totally different experience, a day trip can be, at the very least, a nice break from routine and, at most, a discovery of something worthwhile.

After nearly a month of working on my fence and everything surrounding it, I got to the point where I was literally sick – got a cold – and needed anything but staying home. Listening to travel stories from my buddy, who is blissfully unburdened by home ownership, I figured a day trip was exactly what I needed.

Initially, we were not planning on a trip to Holland, Michigan, but the timing was impeccable and the tulip festival had just kicked off, so Holland it was. My wife wanted to go to the tulip festival for a while, but every year there was always something. Not this time! Despite being sick and running on six hours of sleep, I was determined to make it. Fortunately, Holland is about a 2.5-hour drive, so with little planning, little packing, some coffee, sheer willpower, and energy drinks, we took off as early as we could manage.

The secret to a day trip is to hit all the spots in one day, so an early start and late finish are effectively mandatory. We managed to get to Holland around 11, granted we made a couple of stops, including Zeeland.

Luckily, we managed to make our way in and find parking before it got really busy. Since it was my first time in Holland, I can’t claim to know what it is usually like, but it looks like during the tulip festival the town gets overrun by visitors. Little quiet streets get filled to the brim with people, police control traffic manually, and buses are organized to shuttle people around, not to mention electric tuk-tuks.

I enjoy American themed towns – they are just different. You get a feeling that they are actually made for people to walk and enjoy. But every time I walk around one of those themed towns, I get a little feeling of theatrics… like none of it is real. I guess it is a similar feeling to the renaissance festival – while it is on, people and buildings are there, and once it is done, it becomes an empty field. I guess I feel similar about all-inclusive resorts that have everything on the premises – gym, store, bar, and coffeeshop – simulating a mini-town experience, but you know none of it is real. Nonetheless, Holland is a pleasant town and, considering it is near Lake Michigan and right on Lake Macatawa, there are more things going for it.

The tulip festival takes place on Windmill Island. The island is called so because it has a windmill, and it is pretty neat, both from afar and up close. To get in, it cost us $20 per adult and $10 per child. I guess its running costs are relentless and the entire island needs to generate enough money from just 10 days of a festival… but that is just my speculation. There are a few things to discover, but the main event is the flowers. Now, the website states that there are millions of tulips, and while I didn’t count all the tulips, just walking around, it was hard to see where those millions were. Perhaps millions of tulips are spread all over the township, but Windmill Island didn’t seem to have those millions. I guess it is unfair to compare it with the lavender fields in the south of France, but when you hear the word “millions,” you get the idea that the entire island is covered in tulips, and it wasn’t so.

Since Holland is located near Lake Michigan, I wouldn’t leave before seeing the lake with its spectacular beach. I had never been to the Michigan dunes – something I must see at some point – but man, the sand on Ottawa Beach looked unreal. It feels like you are in the Caribbean, such fine sand with an endless beach. I’ve been told Lake Michigan is deep and never really gets warm, but it sure feels warm, at least in my imagination. It is early May and the weather is still pretty cold, so sampling the water wouldn’t do it any justice, but at some point it must be tried, at least once.

The day trip turned out pretty nice, despite the “millions” of tulips. It is quite interesting to travel far and wide, but often we forget what is just around the corner. I often feel regret that I haven’t visited more local nuggets, and going forward I would like to change that, time and luck permitting.

“Planning per se isn’t good. It’s sometimes necessary, but it’s a necessary evil — a response to unforgiving conditions. It’s something you have to do because you’re working with inflexible media, or because you need to coordinate the efforts of a lot of people. If you keep projects small and use flexible media, you don’t have to plan as much, and your designs can evolve instead.”

— Paul Graham

Rethinking Fence Posts

While I’m not a big fan of construction, nature and prices steered me into the topic, as my fence decided to take a rest.

So for the past week my mind has been preoccupied with thoughts, plans, and calculations about a fence – or, let’s say, a partial replacement. Before diving into my calculations, let me tell you that construction seems to be quite expensive, and fence work is no exception. I roughly figured that replacing a fence of give or take 80 feet would come out to around $4000+ if I were to call a company to do the job. A company would look at my old fence and probably tell me to replace it entirely, since the wood is old enough to remember Jean Chrétien. Judging by Home Depot prices, materials alone would be around $2000.

I wish I could get rid of the fence, but unfortunately I need to have one… so it was time to figure out the best course of action. While I’m not planning to make my fence the best in the neighbourhood, I do wish to fix the issue somewhat permanently. A typical wooden fence can last a while; however, the weak spot is the wooden post – a 4×4 post rots, breaks, and will have to be replaced sometime between 15–25 years, depending on wood quality and conditions. On the other hand, a steel post (such as a PostMaster galvanized post for wooden fences) should last considerably longer, perhaps even twice as long. And while a galvanized steel post costs twice as much as a wooden one ($42 vs $21), there are more factors to consider.

In order to install a new 4×4 wooden post, you need to dig a hole, buy cement, add a bit of gravel, and then set it. Considering you will need 3 bags of cement (quick-post cement), that will cost $33 ($11 per bag at current rates). I’ll skip the gravel price, but you can toss several more bucks into the mix. So at this point we are at about $54+. Now if you want someone else to do the labour, then add another $20 (current rate) per post. Rounding the cost up, that brings us to about $75 per post.

So while a galvanized steel post starts at $42, it has a trick up its sleeve that doesn’t seem to be advertised heavily. Yes, you need a smaller-diameter hole for the post – which cuts down on the amount of concrete needed, and if you’re installing lots of posts, savings on concrete alone will cover the price difference between a steel and a wood post. However, the neat trick is that you don’t need concrete at all. Instead of going the traditional hole-set-concrete route, you can drive steel posts down into the ground with a pneumatic hammer. Now the math looks very different: no more concrete, no more digging or gravel, and you can hire a contractor to drive steel posts into the ground at $20 per post. And so $42 + $20 = $62 per post — that is $13 cheaper per post.

Now I know: we can use less concrete, we can put some leftover glass instead of gravel, we can do the labour ourselves – I’m sure there are lots of “saving” measures that can be employed. However, you can also rent a pneumatic hammer for $75 per day and hammer in as many posts as your heart desires, and oh boy, those posts go in fast. I watched professionals, and those guys hammered in 12 posts in under 80 minutes – which roughly translates to 7 minutes per post. Once the post is in, you can start putting up a fence right away if time and speed matter.

Approximate fence post cost comparison
 (skipping gravel, brackets, and stuff)
Cost item
 – Wood (3 bags concrete)
 / Wood (2 bags concrete)
 / Steel post
Post material per post – $21 / $21 / $42

Concrete per post – $33 / $22 / $0

Labour per post – $20 / $20 / $20

Subtotal per post – $75 / $64 / $62

Subtotal for 12 posts – $900 / $768 / $744

From where I’m standing, galvanized steel posts work out to be cheaper. So the question on my mind is: why are we still installing wooden posts? And why are we still using concrete for steel posts? I mean, for the cost of concrete, we can hire a contractor to drive posts in – fast, professional, and no mess. Not only that, whenever an old post breaks, you need to pull the old concrete out in order to install a new post, if you want to retain the existing post location. Removing old post concrete costs money, but a metal post can be driven in right next to the old one – not to mention that it lasts considerably longer. After going over the calculations, I wonder if it is time for homeowners to rethink fence posts.

The Year That Took

Another year has passed and here I am trying to figure out: was it “better” or “worse”, at least from where I’m sitting. On one hand, the past year could have been a lot worse, but I’m not sure what it says when you start looking at things from a “could have been worse” perspective. Yet another thought ripples through my mind asking: “Does it matter? What are we comparing exactly?”

From a certain point in life, expectations start to diminish as more pressing, close and personal issues occur more often, and the effects can be felt directly. Perhaps it is too early to think and talk about those things, but it is inevitable… well, at least with the current level of technology. I guess we’re gonna get there eventually. If none of this makes sense – it does, since I gave up on the idea of coherent thought today. Just for one day I can let my mind drift and write torn-out thoughts as they float along.

One thought bounces back and forth as I’m attempting not to dwell on it: dead. Past year took away a couple of people. One of them was my good neighbour. Every time I walk by or look out of the window, somehow I expect to see him driving by in his lovely Audi, stopping to say “what’s going on?” or blow leaves onto my property, later saying something like: “I’m getting old… it’s getting hard to take care of things…”. I always imagined myself being somewhat resistant to … loss. While I can stand around a funeral emotionless and stare at people with a poker face, inside things boil unstoppably, quietly blowing past seals, valves, and leaking out in the form of deep uncontrollable sadness.

I guess lucky people pass away fast, but some end up in pain for a while before the inevitable. I think of my aunt who suffered through, and my neighbour. We don’t just stop one day (at least most of us) – we get sick, bit by bit bodies deteriorate. A while back my cousin asked: “why didn’t they go to a doctor if there was a pain” – I assumed it was rhetorical. But I will answer, if not to him, then to myself: because deterioration is gradual. Bodies fall apart slowly, giving us time to adapt to new realities and to deal with it as much as we’re able to – physically and psychologically. As time goes on more and more family and friends will succumb to health issues… and unfortunately a few did this past year. Some had life-changing issues, others… well, let’s hope less so.

Over the last few years, I began contemplating life and choices. In some ways, there are very few choices for a particular person to choose from. I don’t want to go deep into the subject partly because it is a long conversation, partly because I’m nowhere near the end of the contemplation, and partly because today is not the day. However the idea is floating at the top of my waves and so I must proceed at least for a bit. I see the whole choice thing not as random crossroads where you choose to turn left or right, but rather as a recalculated decision that has already been made. It’s like going to a grocery store with a budget. Budget is already calculated, so you buy chicken at a certain price range. Yes, you can buy fancy chicken at a higher price but that will impact other choices by the end of the month or at a later point. So you have a range of decision-making: if there are a few choices in the range then perhaps you can choose, otherwise the decision is already made, you just follow it. Perhaps the grocery store example is too simple, but it illustrates my thought, and in life there are tons of parameters that affect which choices we make and which we just follow. I’m not entirely sure if the level of technology gives us more choices or less. On one hand, as we can calculate more and more, we see less and less randomness, which means more predetermined choices. On the other hand perhaps we can choose better at a point that actually matters. Last but not least is entropy that’s still with us. No matter how much we plan and calculate, some random factor can still throw a monkey wrench into our predictions – which makes life… well, for lack of a better word: interesting.

It’s been 4 years now and the war in Ukraine keeps going. I believe this year has been pivotal not only for Ukraine but also for me. As I learned more and more, my past ideas (and idealism) started to break down, eroding the foundation of my understanding of the world. I’m slowly leaving behind some of my naive ideas of “world peace and love” in favour of cold pragmatism. Don’t get me wrong, I still hope that there is a way that we can all get along… but it is just a hope that one day we’ll get there. The pragmatist in me sees that day as a “not so soon” prospect locked behind technological advancements and humans going to space. But back to the present: it is stunning and inspiring to see how Ukraine fights and operates despite all the challenges.

I hope 2026 is going to be the last year of the war. I believe Ukraine will hold out and win. Odds have been against Ukraine, but despite that it managed to achieve so much in so little time with such limited resources. It is truly astonishing. People will be studying the war for decades to come. Slava Ukraini.

PodOsef – MP3-first, lightweight, simple podcast publishing system.


Over a decade ago I wrote a PHP-based podcast publishing/archive system. The idea behind it was MP3-first: no DB, no complications – just drop an MP3 file into a folder and distribute. The software could generate HTML and an iTunes RSS feed. The main point was simplicity and zero maintenance.

Over the last 10 years, a few issues cropped up. Some were fixed, and a couple of upgrades were slapped on top. However, a few issues (some major ones) remained, and last year I decided to rethink and rewrite the software.

No dream survives contact with reality

The rethinking phase was quite an enjoyable trip. Like a little kid in a candy shop, I was dreaming up anything and everything: rewrite in Java, JS, or Go; add a fancy frontend (to what purpose I wasn’t sure); p2p sync across servers; scaling; and so on.

Finally, the end of 2025 arrived, and it was time to get down to work. As pragmatism settled in, reality hit the fan: make it smaller, faster, and cheaper. Whatever it is, it must work on the smallest droplet, take as little space as possible, respond fast, and require no (or as little) maintenance as possible. With a countdown timer running, the feature set started to shrink rapidly.

Complexity & legacy

Next came a major design decision. A podcast is typically represented by an RSS feed (an XML file), which contains podcast information, a list of episodes, information about each episode, and a URL to the media file. Podcast client software reads the feed and displays it in a beautiful interface, ready for your enjoyment.

But where is the information stored? The internet is full of podcast-oriented CMSs (content management systems), podcast plugins for CMSs, and podcast services. Most of those solutions have one problem: they split information across a database, file storage, and/or config files. As a result we get complexity and, more importantly to me, legacy.

RSS feeds don’t grow infinitely. In theory they can, but in practice sooner or later the feed is trimmed and old episodes are forgotten. Well, not if I can help it – and wouldn’t it be nice to reduce system complexity at the same time?

Choose the source of truth

An audio recording (represented by an MP3 file) can be downloaded, stored, and listened to in any player (burn it to a CD for the old school). But most of the time it lacks the information provided by the RSS feed.

So what if we invert that? What if the source of truth is the MP3 file itself? All podcast information would be stored in the MP3: title, authors, show notes, and cover art. In that case, the RSS feed would simply reflect information already present in the MP3 file (episode).

The Apple Music app lets you edit MP3 metadata (ID3 tags)

In such an arrangement, no database or metadata storage system is required. No need to monitor a DB, no need to back up metadata – almost everything you need is the MP3, since everything else can be recreated from the media file itself, plus a small config for Apple RSS feed requirements.

Make it as simple as possible and no simpler

The prior version was fully dynamic and, in retrospect, that didn’t make much sense, since RSS feeds typically don’t change often. Even if you release new episodes multiple times per day, a statically generated feed is still a far better fit and costs far less.

However, to avoid pauses and polling, the inotify utility was used. It effectively triggers regeneration on file changes, which avoids unnecessary polling and updates the RSS feed as soon as a new episode is uploaded.

Hugo – a static site generator – seemed like a good fit for the task. It’s small, fast, and supports RSS out of the box. In addition, Hugo turned out to be fairly easy to work with, even though I didn’t need much in the way of templating.

Next, it was time to deal with the source of truth. As far as MP3 goes, it has enough pockets to stash your information into. Different versions of software save metadata into different fields, so to accommodate them all – and make it as bulletproof as possible – ExifTool was chosen. It can read metadata from different media formats and write it into metadata files, which are then used by Hugo to generate HTML and RSS.

Main & archive

Now that complexity is addressed, let’s get back to legacy. As I mentioned before, sooner or later podcast episodes are trimmed and, well, lost – unless someone preserves them. In this case it’s fairly easy to organize an archival version of the podcast. Since all the information is contained within the MP3 file itself, all that’s left is to download it.

Taking this idea a little further: an archive can be organized simply by deploying PodOsef along with a downloader (already built). It literally watches the main RSS feed, downloads MP3s, and with a little configuration you’ve got yourself an archival (so to speak) version that keeps downloading new episodes and keeping old ones.

This can be used as a cheap form of scaling, or perhaps community-driven archiving. However, I haven’t put much thought into it, and I have a feeling there might be a better way to scale – but at what cost, I don’t know.

And so…

We got ourselves an MP3-first, simple, lightweight, cheap, minimalistic podcast publishing system – with an archival option – that’s containerized under 250 MB and can run on a small server/instance/droplet, or even on an old machine. 

PodOsef is open source. You can modify it as you see fit, or drop me feedback. While I can’t promise feature fulfillment, I sure do appreciate it. For more technical information, please go to the GitHub repo: https://github.com/meirka/podOsef

Bad luck, that’s all it was

Today was supposed to be another workday—routine and busy. I had a few things I wanted to finish, but some unfortunate news came in the morning. Not unexpected, but it pushed my already gloomy mood to the bottom and drove my thoughts even deeper into an endless state of wondering.

I’ve been wondering and pondering the meaning of life for a little while now… I don’t know, and I might never know. But last year, as my neighbour was gearing up to go to Mexico for the winter, I got a bad feeling. I don’t know how to describe it, but it felt like he was taking his last trip… like I might never see him again. I don’t know why, I don’t know how—it was just a stupid feeling.

He went to Mexico many times before—no issues—and every spring he would come back and things would carry on. Not this time. He got an infection sometime prior (bad luck), and the troubles started on the way to Mexico. As far as I know, he tried to get help in Mexico, but none of it worked, and he was back in Canada a month later.

Don was my incredibly awesome neighbour for nearly a decade. He’s been in the hospital for the past couple of months, slowly withering away, while I’ve been hoping for a miracle. The first time I visited him in the hospital, I had my hopes up. I hoped he would recover—that we’d spend at least one more summer having drinks on odd evenings, and he’d laugh at my problems, occasionally dispensing wisdom in the form of his seemingly endless life stories, or just telling jokes and making fun of the world.

I don’t exactly recall how we met the first time, but I’m sure he invited me for a drink, and that’s how our relationship began. Since then, we hung out quite a bit. He had an interesting character: on one hand stoic and nonchalant, on the other fiery and determined. It takes courage to call out stupidity right to your face, and he did—every time I cooked up yet another “brilliant” idea, like building a shed out of 1×2 or 2×2 wooden planks. Needless to say, his advice didn’t go unnoticed (I didn’t build that shed). He had a lot of experience, and I was happy to receive some of it.

I really appreciated his take on my issues (and oh boy, I’ve got some), especially when my aunt passed away. He told me to go and pay my respects no matter who said what and why. In retrospect, he was absolutely right.

I grew up without a dad, and my mom did everything she could for me. I never really dwelled on it until fairly recently. On one warm, breezy night, drinking with Don and talking about life, I started to wonder if that’s how it should’ve been. Moms are always protective, but what about dads?

I didn’t really have an answer, but what I could gather is that dads seem to give you that tough pill to swallow: if you’re right, you’re right—and if you screwed up, then you’re wrong, and let’s fix it. I don’t know how true my idea is, but that’s how I perceived Don. He was always helping whenever I needed it: advice, tools, knowledge, even a hand when he could.

He always had a story to tell, advice to spare, and he never pretended to be any more than what he was—French Canadian with a big heart and a soul.

Poor Man’s PiTest

Unit testing, as important as it is, is still treated as an afterthought. First, we write production code and then tests — if we have enough time and, more importantly, the will. Unfortunately, the natural result of this process is missing coverage, weak or absent assertions, and, more importantly, a lack of real exercise of the production code. I believe these issues are well known, but somehow they’re still not important enough to change the process. After all, we have production code; let’s ship it — “Damn the torpedoes, full speed ahead!”


In my opinion, this issue is well addressed by Kent Beck and Robert C. Martin (Uncle Bob), who emphasize starting with a test. Unfortunately there seems to be lots of fluff, buzz and general misunderstanding of TDD. No, it is not Test-First. No, there is no magic sauce. No, there is no need to read tons of books or go to fancy lectures. After reading a few books, watching a few videos, attending a few fancy lectures and a few years of relentless practice, I can definitely say that all you essentially need is to read Kent Beck’s book – Test-Driven Development: By Example, watch Robert C. Martin and stick to The Three Rules of TDD. While Kent and Robert do not address every single scenario and issue, the above resources are more than enough to extrapolate and adapt the technique, let’s say to microservice architecture (which is not originally addressed). Now I’m not saying those are all the resources that you will ever need, but those are essential for TDD! Last but not least, if you don’t know how to do dependency injection without @Autowire (unfortunately I’ve seen that), it does not mean TDD sucks, it means you lack knowledge. TDD is not magic or a Swiss Army knife, it is a specialized technique for writing code independent of any specific platform, framework or language.

Example of useless 100% code coverage

Unfortunately TDD is not widely adopted, and even if it was, we are still subject to mistakes — we are only human. Under these conditions we need a solution that does not rely on a human. One bad solution is code coverage. Code coverage has been around forever and is loved by managers as it neatly translates to charts, means little, and can easily be faked by developers. Code coverage has its uses, but it is useless in determining how well production code is actually tested. But don’t despair, we do have a solution — mutation testing. Mutation testing has a simple premise: change production code, see if any tests fail. If nothing is failing after the change, that means insufficient testing. In an inverted way it sure resembles TDD. While the premise is simple, execution is quite expensive! See how long your test set takes, then see how many logical and state changes can be applied in production code, multiply those numbers and you see how much time mutation testing will take — in short, a while for a sufficiently large project. That is probably the reason we don’t see mutation testing everywhere.

Mutation testing is hard to fool

Fortunately the Java world is blessed with a modern tool for mutation testing – PiTest. It provides lots of features in its open source form. Even more features come with the commercial extensions, which integrate into a modern pipeline (or dev machine) and provide quick feedback to developers waiting for code review on their code changes. I wholeheartedly suggest buying a license and using the full power of mutation testing if code quality is important. Unfortunately my company, for various reasons, isn’t quick to sign up, despite claims to strive for quality. After a proof of concept, presentations, near begging and a final rejection, I fell into depression. I really wanted to use PiTest for tangible results and partly because it would have made my life a lot easier and the life of junior developers a lot harder – since I would not have to spend any time figuring out if their test code actually tested enough or anything at all (yeap, I’ve seen those cases too).

Finally, I realized I’m an engineer; my realm of possibilities lies far beyond microservices. I decided to build a “Poor Man’s PiTest”: a small tool that takes the open-source core and combines it with the power of Bash, Git, and a few other Linux commands. That gave me the ability to build only the projects that are needed, run PiTest only on the changed classes in a multi-module Maven project with a mix of JUnit 4 and JUnit 5 modules, perform timing analysis, log everything for debugging purposes, and optionally skip builds and/or focus on a single module if needed. So far it works well and, let me tell you, junior developers just “love it” — especially when I give them a long report of everything that’s been missed.

I figured someone might be in a similar situation, perhaps needs a bit of inspiration or an example, so I created a GitHub repository to share the script.

Thank you, and I hope the script will be of some use.