Mon 07 September 2026
Solve the Right Problem
The interesting thing about the startup world is that progression is typically, 1. working on someone elses idea. 2. working on your own idea, 3 funding other people to come up with ideas. A common mistake for many of the YC college dropouts tend to be; build first, ask questions later. When you're YC and are hedging your bets for a slice in a few potentially great businesses paying for this education is cheap.
It is common for startups to run head first through the phase: build it and they will come.
we built a couple things that just no one wanted and then realized we're going about this the wrong way.
Christina Cacioppo (Vanta) 20252
This mistake isnt limited to the young cohort of YC startups. This is a fallacy that cause many Software projects to fail, it is a lesson that all creators have to learn.
Software Engineers
Software engineers hit a maturing point when they make the shift away from accidental engineering to intent driven decision making.
Early in their career they tend to enjoy the exploration of new ideas and the novelty of new software in business. Often referred to as CV driven development. They dive head first into developing features or solving problems. This characteristic isnt inherently a problem when guided by engineers that have their fair share of war stories, however as every engineer comes to learn; diving head first into the code will lead you down a painful path.
Established engineers approach a problem with a focus on what the user or customer intends to do and avoid relying on codified solutions.
It is still easy for experienced engineers to fall into the trap, blinded by excitement or neglicting to push back through fear or through finding it easier to go with the flow than challenge and presenting an alternative.1
Without establishing customer intentions we are building with hope as the dominant strategy and are leaving our product up to chance. Leading with intent helps to create things that have purpose.
The most noticable example that highlights this behavour is when an engineer manages to close out work without writing code or when they establish that work shouldnt be done until something fundamental is proven. This can be as simple as, "is anyone asking for this?".
The Users
Companies place a heavy emphasis on valuing the customer as a means to avoid repeating their early mistake. The truth is we shouldn't be valuing what they say but we must try to care about the same things they care about. We need to discover their intent.
Product market fit is about creating a product that serves the intention of a large enough market. Before we can create a product we need to figure out what the customer wants to do and then figure out how to serve them. We can't setup a pillow renting business before we have asked if anyone would actually rent a pillow.
The "Customer Obsession" mantra isn't just corporate shill and it is a common value among companies because it is easily forgotten.
If I'd asked customers what they wanted, they would have told me, 'A faster horse!
Henry Ford
Steve Jobs used this quote to highlight why giving the customer what they want doesn't work. This doesn't mean you shouldn't speak to customers, but you should figure out not what they want but what they want to do. In the Henry Ford example, they want a faster horse, but their underlying intention is to get from A to B at speed.
The user will tell you want they want but it is our job to find out what they need.
Another easy habbit to fall into is being quick to provide answers without the full picture. Your first solution is often never the best and you might find that the customer might have already tried it. Instead of providing the answer, our first step should be to question why they want the answer in the first place.
Trying
Figuring out how to address a customers need is hard work and I've found people tend to be alergic to hard work; often coming up with reasons why their market is build differently or how something so common as product market fit doesnt apply to them. The failure of startups is a tale as old as time and the "I'm not like everyone else" is probably the reason people fall prey to common pitfalls.
There is nothing that should be more exciting than a hard problem, hard problems will make most people give up. This makes solving it all the more enjoyable.
Tue 01 September 2026
Random
Humans and computers are really bad at being random. An article recently published by the FT examined how people behaved under seemingly random situations and how efficient computers are at predicting our decisions even when we aim to act as randomly as we can.
Computers are equally bad at acting randomly; yet this hasn't stopped us from attempting to develop algorithmic approaches to generating randomness. Random number generators have many applications, from generating worlds , running probabilistic simulations to cryptography.
Randomness can be split into two categories, True Randomness and Pseudo Randomness. True random may only appear in life and nature where it is impossible to predict the next state despite knowing the current state. On the other hand even though pseudo random appears unpredictable it can be replicated if all the starting conditions are known.
Quality of Randomness
There are several qualities to the algorithms that provide us randomness by which we can compare them. The first quality is the algorithm's "period", the number of time we can generate an output before the numbers start to repeat themselves. The second is the number of dimensions the algorithm can pass the spectral test.
In the 1940s von Neumann presented the middle-square method for computing random numbers and it worked as follows:
- Take an n-digit number
- Square it
- Take the middle n digits from the result
The alternative was to find a random number from a book. Whilst there's no set period for the middle square method it is often short and unpredictable which proves to be inconvenient in most applications.
An improvement was made in the 1950s with the development of linear congruential generators. However these fall short on spectral tests which means they start to develop hyperplanes in larger dimensions (the English translation: you start to notice patterns in 3D).
There are a number of tests that are used to measure the quality of a random algorithm which have become known as the Diehard tests. Among them is a suite of tests called "Craps test" where the algorithm plays 200k games of craps and the count of wins and throws should follow a specific distribution.
Contemporary Randomness
All algorithms that generate random numbers start with what is known as a seed. The seed is a number that is used to provide an initial state that all future states are based on. This allows us to replicate random generation or seemingly random simulations when provided with the initial seed.
There are some situations where a seed is not explicitly given when generating something random - however typically your computer will use the current time as a substitute for the lack of explicit seed.
Most contemporary languages such as python use an algorithm called the "Primitive Twisted Generalized Feedback Shift Register Sequence" this is known more commonly as the Mersenne Twister. Due to the existence of a Mersenne prime constant in the algorithm. You can read the C implementation of MT in the python source.
A note on Mersenne primes: these are prime numbers that are (2^n) - 1. One less than a power of two. These primes happen to be the quickest to prove as prime and therefore make up all the largest known prime numbers.
The period of the Mersenne Twister is (2^19937), which is a number I don't have time to type out. 19937 happens to be that Mersenne prime number in the algorithm and the algorithm passes spectral tests up to 623 dimensions.
Cryptography
The realm of cryptography relies on crypto-secure pseudo random number generators (CSPRNG). These are used when generating a password or private/public keys for encryption like RSA. They are required to be both random and unpredictable. Unfortunately the Mersenne Twister isn't safe for cryptography since with enough observations it becomes predictable. As evident in the blog series: Cracking Random Number Generators
Over time we've seen the pseudo random algorithms required in cryptography being broken and methods discovered in order to predict the random number used in the system. Cloudflare proposed a solution to this, instead of having the CPU generate a number using a predetermined algorithm, have a wall of lava lamps and take a photo of the wall whenever you need a new number. This works because images are stored on a computer as numbers and there is naturally occurring randomness which is extremely hard to reverse engineer.
Mon 24 August 2026
Python Under Pressure
The first software book I bought was Effective Python by
Brett Slatkin. The book distills tips and tricks learnt
by Brett over the course of his career. It was in this book
I first encountered how to use the enumerate keyword. Over
the course of my career a new hint like this one has sparked
joy and I've experienced first hand how pulling one of these
out of the back pocket during a live interview can intrigue
an interviewer.
One can speak a language their whole life and every so often come across a new word that you've not encountered before but it does a very good job of describing the current situation. The same happen in software.
Python is a language with a large standard library that
offers many tools, so much so that you can even import antigravity.
Here's a shortlist of some of the tricks you can do when you
have to write python under pressure.
Modular Operator
Running into a situation where you need to cycle through
indexes in an array the modular operator % is the tool of
choice.
Using it we can have x cycle from 0 -> 5 and back to 0. It's application extends to explaining how hash look ups work in a key value store and providing an answer to a simple question like how much remains after dividing 5 by 3.
# x cycles from 0 -> 5 and back to 0.
x = 0
x = (x+1) % 6
# How much remains after dividing 5 by 3
>>> 5 % 3
2
Floor division
When we don't care about the remainder we can use a floor division to provide a nice round int. This answers the simple question, how many times can 4 fit into 11:
>>> 11 // 4
2
Divmod
When we can't remember if we should be using % or // in
the middle of a live interview then we can use the builtin
keyword divmod to give us both answers.
>>> divmod(6, 4)
(1, 2)
dict.setdefault
There are some tricky problems that want you to set a key if
it doesn't exist in a map but if it already exists then
avoid updating the map but ensure the value being set is the
same as the value that has already been set. Obviously you
can do this without setdefault.
x = {"foo": 4}
new_value = 10
old_value = x.get("foo")
if not old_value:
x["foo"] = new_value
else:
if old_value == new_value:
raise
Here's how you can do it with setdefault.
x = {"foo": 4}
new_value = 10
old_value = x.setdefault("foo", new_value)
if old_value == new_value:
raise
Setdefault will insert the key with the new value if the key isn't already in the dictionary. When it is already in the dictionary it returns that value otherwise it sets the provided value and also returns that value.
Greatest common denominator
If you need to perfectly tile a 21x35 rectangle with squares, what is the size of largest square that will cover the area of this rectangle?
The answer is the largest number that the two numbers, 21 and 35, can be divided by.
>>> import math
>>> math.gcd(21, 35)
7
Thus the largest size square is 7x7.
Prefix sum
Prefix sums is a common technique used to solve coding problems such as "Subarray Sum Equals k". A prefix sum at index i represents the sum of all items from 0 to i. We can create a prefix sum in python using itertools.
>>> import itertools
>>> list(itertools.accumulate([1, 3, 4, 3, 2]))
[1, 4, 8, 11, 13]
Defaultdict
Defaultdict is a classic tool which allows you to specify
the default instantiation for a key. If you need to track a
list of elements for specific keys you can instantiate the
default dict with list. To avoid checking if a key
already exists and creating a new list if not.
>>> from collections import defaultdict
>>> tracking = defaultdict(list)
>>> tracking["x"].append(1)
>>> tracking
{"x": [1]}
It also plays nicely with counting.
>>> from collections import defaultdict
>>> tracking = defaultdict(int)
>>> tracking["x"] += 1
>>> tracking
{"x": 1}
Heaps
Tracking key usage or needing a priority ordered queue will require using a min/max heap. Fortunately python offers methods that transforms lists into these heaps.
from heapq import heapify
queue = [3, 1, 2, 4]
heapify(queue)
Relying on heappush and heappop allow us to dequeue or
enqueue items to our heap while maintaining priority order.
deque vs list
I've covered deque before in essence we can't always rely on the builtin list as they are dynamic arrays, we need to remove from the front and pop from the back in constant time. The deque is a builtin solution for linked lists.
from queue import deque
q = deque()
q.append(1)
q.appendleft(2)
q.pop()
1
Bisect
Another one already covered.
This is Python's own implementation of binary search. If we
are given a sorted array and wish to insert a new item while
maintaining order we can use bisect_left.
from bisect import bisect_left
items = [1, 2, 4, 5, 5, 6]
bisect_left(items, 5)
3
Mon 17 August 2026
Release sooner, Learn faster
Startups fail for the same reason you might. The typical failure case for startups include no market need and failing to pivot quick enough. These are also risks faced by larger companies but they're harder to notice. A typical solution from leadership is to remove processes and promote behaving "like a startup".
One does not throw process out the window in order to succeed. If this were the case; injecting chaos into a team would be the dominant strategy.
The key to running a successful product team is to establish a culture that seeks to aggressively shorten the time it takes for the team to make mistakes and learn. Shipping the wrong thing in one week is better than shipping the wrong thing in 6 months.
Long Term Risks
Long term plans lack the existence of genuine feedback, instead feedback is received on the idea in our head and how the idea is perceived in someone else's head. This misalignment is one of the risks we bake into the development cycle among others that aren't obvious when we have a long development horizon.
A plan is the route we take from the current state of the world A and the world we wish to exist B. When we commit to the plan we are hoping that this new world will be the place everyone wants to be. If 11/12 startups fail this indicates we are generally bad at envisioning futures.
Quarterly releases has the risk of assuming what is true today will still be still in three months and that everything will go according to plan during this time and not be derailed by something that takes priority.
If things do go according to plan and we get to release, the best case scenario is that the vision is only three months old. However in reality one learns, ideas mature and the state of the real world can change in a short time.
Long on-going projects are hard to back out of. Admitting defeat is hard especially if a competitor fails finding product market fit for the very next thing you're waiting to release. There's the sunk cost fallacy, political stake, emotions and the missed opportunities from having to sit down and crunch in the last minutes of release. Even having your head in the problem can help you realise that it might not work out and we have to ask ourselves if we've reached the point of no return.
A project that is under an on-going and long product iteration cycle needs to constantly reassure stakeholder that everything is alright and will be alright. Additionally there's the pressure being applied from shiny new ideas that have novelty appeal and are more exciting to talk about than the thing we've been actively working on for the last two months.1
These are all systemic risks that are not built into the product but are built across the delivery process. A company that releases quarterly has a minimum reaction time of 3 months.
What can we do?
We have two goals. Find out what is valuable and minimize the time it takes to deliver that value. Ideas are cheap, customers pay you for what you release they don't pay for what you plan.
Learning comes from the user and you can skip discussions or second opinions. Getting something into the users hands is the opportunity to learn far more than you might from a peer. Spending 2 weeks to fail is far cheaper than spending 3 months and now you can take what you've learnt into the next cycle.
Successful startups are skipping advise from the experts and just seeing what works. Senior leadership can sometimes hold innovation back and a little naivety can go along way. We need maturity to say "I don't know" and bravery to say "Let just give it a go".
Identify the processes that are busy work, work that feels productive but slows down your ability to release. This could be planning meetings with teams that have nothing to do with your project.
Focus on development that gets you signals instead of releasing fluff. You don't need to release the entire picture, if you have the opportunity to release only one thing and that thing helps you determine if your vision is wrong, you shouldn't be building anything else.
Do some now
Delivering something now is better than delivering it all at later.
Don't delay learning, if you release a product to the world after months of working on it, you're going to be doing a lot of "learning" after that release. Only if it's not incredibly hard to separate that parts that are cruft and the parts that are valuable in this release - it is far easier to learn iteratively than it is to learn while you're putting out fires.
There are no rules, you are allowed to release something and have users find it by chance or selective introduction. Releasing a feature is different from announcing a feature. Some users might never come into contact with the feature, and those that find it might ignore it since it doesn't fit their use case. It is fine for things to not be a fit for all customers, but the users that find it's useful have had value delivered to them without you needing to complete the entire project. To these customers you've done this quicker than expected and now you're being paid earlier than expected.
Value can be delivered even if it requires manual work. Managing to automate 40% of the workload while requiring the rest to be fine-tuned from the user will be seen from the determined customer as saving them 40% of the time, they won't see the job as half done. Their concern is getting to market, they have their own competitors and you've just given them a 40% head start. Had you not released early, they would have to do the 40% themselves anyway.
Waiting to serve all use cases delay some of your customers when they could be using that time to make their money. Doing 20% of the work might be 10% more than a competitor, and releasing sooner positions you better and can de-risk churn.
Are your customers even asking for it? You can get through releasing 10% of the plan and suddenly all your existing customers adopt the feature without you needing to sink time into the other 90% of the work that you had assumed would be needed to convince them. Ditch the plan, ask them what's next.
If there's one truth or take away from this post; it's that the importance of something being done diminishes over time so the sooner something is delivered the higher it's overall impact. No matter how small.
-
Often out leaders just need to be unconditional hype people, always gassed about the work we are doing. ↩
Mon 27 July 2026
Accountability
The strongest leaders aren't afraid to recognise failure. Some are even demonised for shutting down parts of a business that aren't working but this is no different to removing a lazy member from the group project. All teams need mechanisms to ensure accountability. Accountability maintains high performance. It's easier to remember the Russian proverb:
доверяй, но проверяй
"Trust, but verify"
Having a slacker in a school group project can become the cause of frustration. Even high performers can be brought down if they see what the shirker can get away with. While we are in school a project might last 1-3 months and you can choose to avoid teaming up again. In business you might be stuck with this person indefinitely.
The sooner problems are addressed the quicker things can turn around. All teams need mechanisms for accountability, these can be daily stand ups or bi-weekly sprint goals. Even teams that you assume are high trust environments have mechanisms for commitment; such as equity tied to targets and vesting periods among co-founders and early employees. Otherwise we risk awarding someone else for the work we put in.
Smaller companies can be better at identifying when things are not working since a single person in a team of 20 accounts for 5% of the business. In larger enterprises people may hide among the numbers if there's no culture of accountability.
Why do we find it hard to call out under performance or feel bad when we have to kill a project?
A conversation on accountability is much harder to have if the project has been going on for some time. The best way to avoid the hard conversation is to set expectations upfront. If you've missed this chance then now is better than later as delay could cause more damage if these crucial conversations are forgone and an opportunity to deal with it is lost.
Shirkers shouldn't get a free ride while a group toils. They can skew stakeholder expectations and start affecting your own performance negatively. It takes a bit of bravery to hold other to account but in a team the burden must be shared.
It is easy for high performers to get fed up if they are not being recognised when they're holding up a team on their own and you could be left holding all the shirkers.
If you really want your readers to get invested in the story, kill off a character, this is a good way to indicate that the stakes are real. Do you think Game of Thrones would have been a hit if everyone survived? How come we aren't resurrecting Boromir or Háma?
Investors
One of the oldest and most studied behavioural patterns among investors is called the disposition effect, built on prospect theory in behavioural economics.
This effect explains that investors are often quick to sell their winners and hold their losers for too long. Studies have found that people are loss averse, they have a stronger negative reaction to the same situation when it is framed as a loss than if it were framed as a gain. These behavioural biases lead us to sub-optimal decision making. Investors will frame holding a losing asset as only a loss upon selling, while holding may lead to the hope that they might one day break even.1
Cut the losers, hold the winners.
Pragmatism
Not all work needs to be delivered, but evidence of progress needs to be made. If someone has sunk a month of their time and has nothing to show for it this is the slow approach to failure, at the end of a month you need to show a document that outlines the challenges and difficulties and the approaches you took to make progress as well as some potential avenues which may lead to successful outcomes, at the very least.
Essentially you need to go from 0 to 1 in delivery or evident as best as you can to show that you're moving off the starting point. The following month you can't be starting from 0 otherwise you may as well just have been on holiday.
This is the R in R&D.
Excuses
Avoid leaders that blame market forces. A leader that is quick to point at external factors for failure will be as quick to claim the success of others.
When we succeeded it was all part of my plan and when we failed we were just unlucky. It never seems to be the case that we were lucky to succeed, despite our fuck-ups. If we want to use market forces as an excuse then we should accept that we may succeed despite how poor our decisions were in hindsight.
If we fail to be accountable we will fail to recognise when we are in control and when we are not. When shit hits the fan you want to be surrounded by people that know the levers that can help us get out of a mess, not around those that shrug and say "well what could we have done?".
Taking accountability and owning the failure actually helps you avoid falling for the same traps and making the same mistakes. Leaders that show vulnerability are more likely to build trust and stronger collaboration.
Find people that own up to their mistakes, take accountability and make an effort to grow, but make sure to verify.
References
-
A note here, if you held stock in Bank of America in 2007, you would have to wait 18 years until you would have seen the asset reach the same price again. ↩