I’m on a mission to answer a simple question: Which abstractions should be used when?
From the moment I learned my first abstraction, I was hooked.
This fascination continues to shape how I think about software and has led me to complete a PhD.
On this channel, I share practical frameworks, mental models, and real-world examples to help you make better decisions as a developer. Whether you’re a student, entrepreneur, or seasoned programmer, the right abstraction can make all the difference.
I make videos on:
1. Choosing the right abstraction.
2. Reducing complexity without losing flexibility.
3. Decision-making tools for scalable code.
4. When and why to make trade-offs.
If you’ve got a question, challenge, or story, email me—I’d love to hear from you.
Note: Some links on this channel are affiliate links. If you buy through them, I may earn a commission at no extra cost to you.
Christopher Okhravi
I’ve always loved interactive coding tutorials.
But now… they’re getting supercharged by AI.
+ Natural language feedback.
+ Explanations for anything.
+ Personalisation.
+ Mock interviews.
And we’re probably only scratching the surface.
I’ve recently partnered with Educative.io and the space is moving really fast.
Currently, they’re running a 30-Day Coding Challenge with some sweet prizes. If you’re looking to practice anyway, why not hit two birds with one stone?
👉 www.educative.io/games/coding-challenge?aff=BaLM
(Bonus: My link also gives you 55% off a plan! 😬😬)
1 month ago | [YT] | 7
View 0 replies
Christopher Okhravi
“I’d rather make dollars than make sense. “
The rappers had it figured back in the 90s.
Principles are great.
But principles don’t ship products.
Rules are rules until pragmatism says otherwise.
Sometimes we face a choice:
Do we keep searching for the “best” solution?
Or do we bend the rules and deliver value to the customer today?
Just because value today often has to take priority doesn’t mean principles are useless.
Maintainability keeps us alive in the long game.
But if we don’t provide value now, we’ll be out of business long before we get there.
Our job isn’t to write the most elegant code.
It’s to create value today while keeping the ability to create value tomorrow.
Have a look at the image.
The ideal level of pragmatism is where the two lines meet.
So, where do we find that point?
In the early stages of a venture, the cost of technical debt is low because we have so little to maintain. But the opportunity cost of shipping too slow is huge. (Top image)
But as our venture matures, technical debt can spiral out of control and far outweigh the cost of moving too slow. (Bottom image)
Agree?
My book, The Object Oriented Way, is about writing maintainable software. About knowing when to follow principles and when to break them.
Check it out!
Link in the comments.
2 months ago | [YT] | 31
View 3 replies
Christopher Okhravi
Rules are rules… until performance says otherwise.
Most of the time, the real problem in software isn’t speed — it’s change.
That’s why I believe maintainability matters far more than performance optimization.
Generally, writing maintainable code means writing code that’s less performance-optimized. And that’s fine.
Generally, when we have to choose between the two we should choose maintainability. It keeps our systems alive in the long run.
But every so often, performance IS the problem.
And in those rare cases, we should break whatever rules we need to get the job done.
Take immutable lists. They’re great for reasoning about code.
But every time we insert in the middle, the whole list has to be rebuilt.
In many domains, that overhead is fine. In others, it’s a deal-breaker.
That’s when we open the escape hatch and choose a more performant tool.
Another example: denormalization in relational databases.
The fact that we sometimes have to denormalize doesn’t make normalization useless.
The default should still be to normalize. Even at the cost of performance. But only until performance becomes the higher priority.
We don’t follow principles for their own sake.
We follow them until either performance, or pragmatism, forces us to trade them away.
But let’s talk about pragmatism tomorrow.
Now, have a look at the image.
The ideal level of performance is where the two lines meet. But since computers are so fast these days, I’d argue the customer dissatisfaction line drops much faster than drawn. Which moves the ideal point further to the left. Which is why I say we should default to maintainability.
My book, The Object Oriented Way, is about writing changeable software and knowing when to follow principles, and when to break them.
Link in the comments.
2 months ago | [YT] | 46
View 7 replies
Christopher Okhravi
Don’t use getters and setters. They break encapsulation.
That’s what they say.
They say we’re merely masking the ugly truth. That we’re directly accessing naked data.
But I don't get it.
Getters and setters are just methods with different syntax.
They give us a place to intercept the call to run arbitrary code.
Just like methods do.
We might ask for the damage of an attack and get back an int. But under the hood, the class might store it as a double. Or store nothing and compute it on the fly. That’s still encapsulation.
The underlying field might be expressed as a double even though we get an int back. In fact, the class might not even have any underlying field. The value could be computed.
The only reasonable argument against getters and setters that I can think of is that they promote a “Tell don’t ask” mindset. And sure, that’s a useful principle. Most of the time. But not all the time.
In practice, I’ve broken that principle many times and found my code to get clearer as a consequence of doing so.
Philosophy aside, there’s no pragmatic difference between using methods and getters and setters. Both hide the implementation details.
Getters and setters are just a convenient way of expressing nullary and unary methods when it’s intuitive for callers to use the assignment operator instead of method invocation syntax.
That’s all.
Tell me why I’m wrong.
My book, The Object Oriented Way, is about writing changeable software and cutting through dogma to see the connections between patterns, features, and principles.
Link in the comments.
2 months ago (edited) | [YT] | 33
View 8 replies
Christopher Okhravi
Functional programming does not scale.
That's only one of the lies people tell themselves to avoid learning it.
But in the 80s and 90s, people said the same things about object oriented programming:
❌ Too much indirection.
Layers of abstraction will make code impossible to follow and debug.
❌ Performance won't scale.
Dynamic dispatch and object overhead will drag big systems down.
❌ It's an academic fad.
Not practical for real software.
❌ Too hard to teach and learn.
Thinking in objects instead of procedures is unnatural and confusing.
And yet, here we are. With an uncountable number of systems running OO code quite well.
The skepticism around functional programming today is just history repeating itself.
Since I don't have personal experience working on large FP systems, I love hearing from those who do. Have a look at the screenshot.
Oh, and if functional programming intrigues you and you already know some object oriented programming you might enjoy my book, The Object Oriented Way.
Link in the comments.
2 months ago | [YT] | 44
View 12 replies
Christopher Okhravi
Is subtype polymorphism overrated?
Every problem can be solved through parameterization. That's what procedural programming always did. And it’s just as Turing complete as object oriented programming.
So why bother with subtypes?
Why not just think more deeply about our problems until we figure out how to parameterize them?
Because sometimes there’s no obvious way to parameterize. Every solution feels awkward.
Parameterization captures variation as data.
Subtype polymorphism captures variation as behavior.
Instead of having to use the same algorithm for every case we can use completely different algorithms. As long as they share the same interface.
The point isn't that subtyping is necessary.
It's that sometimes it gives us solutions that are easier to see and reason about.
But remember:
That's exactly what people once said about inheritance. That it was more intuitive and would lead to simpler solutions. But we all know how that story ended, right?
What do you think, should we prefer parameterization over subtype polymorphism?
This post is a modified excerpt from my book, The Object Oriented Way, which is all about writing changeable software and seeing the hidden connections between patterns, features, principles and paradigms.
Link in the comments.
2 months ago | [YT] | 42
View 8 replies
Christopher Okhravi
Stop Optimizing The Wrong Things.
Knuth famously said that “programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs”. That we should “forget about small efficiencies, say about 97% of the time.”
It was relevant in 1974, and just as relevant in this age of vibe coding.
Don’t obsess over performance before you know where it matters.
Computers are fast.
What we need is not micro-optimization.
We need simplicity and the ability to change direction fast.
Optimize for:
⏵ Solving the right problem.
⏵ Shipping value.
⏵ Keeping your solutions malleable enough to pivot.
Products don’t fail because a loop is 3% too slow. They fail because nobody needs them.
Yes, performance can matter. But only after you’ve measured and learned where it matters.
Build for learning. Build for change. Then — and only then — possibly optimize.
📕 Download my book! It deals with writing changeable software.
Link in the comments.
4 months ago | [YT] | 77
View 7 replies
Christopher Okhravi
Such a missed opportunity, multicast delegates are.
In C#, delegates are multicast by default.
That means you can use the + operator to combine multiple methods and invoke them all in sequence.
Action a = Method1;
Action b = Method2;
Action combined = a + b;
combined(); // Calls Method1, then Method2.
Powerful?
Sure. But also… disappointing.
Here's the missed opportunity:
The + operator could have been the function composition operator.
That would have been way more powerful.
Multicast delegates just run all stored methods in order.
No passing output from one into the next.
No return value chaining.
Just fire-and-forget.
Only the last return value is kept.
That’s not composition.
That’s broadcasting.
And it’s a shame.
We were so close to having function composition as a first-class citizen in the language.
Delegates gave us a glimpse of the promise of functions.
But multicast delegates failed to keep fulfilling on that promise.
My book, The Object Oriented Way, explores the overlaps — between patterns, features, and paradigms.
Link in the comments.
4 months ago | [YT] | 28
View 3 replies
Christopher Okhravi
If you understand Strategy, you understand Bridge.
Strategy is a concretion composed with an abstraction.Bridge is a concretion composed with an abstraction… that’s composed with another abstraction.
In other words:Bridge is what happens when you nest Strategy.
Strategy helps you vary what you do.
Bridge helps you vary what you do and the context in which you do it.
Instead of just varying an algorithm we can also *vary the context in which it runs*.
Just like you can pair any camera with any lens — as long as they follow the same interface — bridge lets you combine elements from two type hierarchies.
📕 My book, The Object Oriented Way, doesn’t ask you to memorize patterns.
It helps you understand what they really mean.
Link in the comments.
4 months ago | [YT] | 51
View 3 replies
Christopher Okhravi
Composition is good. But with dependency-injected subtyping, it’s better.
Object composition alone does not solve the problem of tight coupling.
If we compose with a concrete type, we’ve avoided inheritance but still hardcoded our dependency. We’ve traded one kind of rigidity for another rigidity.
What makes composition powerful is when the composed object is an abstraction — something that multiple concrete types can implement. And when that abstraction is passed in from the outside, rather than created from within, our code becomes more modular.
Instead of baking in behavior, we inject it. Instead of depending on a specific type, we depend on a shared contract.
Composition is truly powerful when we couple to abstractions and inject our dependencies.
📕 My book, The Object Oriented Way, explores this and other ways to write changeable software.
Link in the comments.
4 months ago | [YT] | 46
View 3 replies
Load more