In 2005 I stopped hating the code I wrote. I felt I had reached a milestone in my career. After 5 years, I one day looked at some code I wrote 6 months ago and went “Man… I actually like this, and can understand it!” That often never happened. My gut instinct was to just rewrite. Suddenly I could start using things I wrote awhile ago in new projects, with confidence and only minor modifications.
Yesterday, rewriting an SDK I wrote 4 years ago, and I would not write it like that today. That tells me I’ve made a lot of progress and changed in 4 years. Skill progress! 😁
When I try to sell people on Functional Programming, I’ll say things like “Imagine a world with no null pointer exceptions”. That’s a bit misleading as I’m actually referring to is the power of a sound types.
However, it’s assumed in Functional Programming that do not have runtime Exceptions at all. Instead, functions that can fail will return if they worked or not. When referring to this, people will sometimes say “Errors as Values” instead of Errors being a runtime exception that has the error inside of it. That belief system is what I want embraced, not sound types as many are using dynamic languages, so the belief is more impactful in those type-less areas.
It’s quite an alien viewpoint, and hard to visualize how you’d program this way if you’ve never been exposed to it. This is especially true if you’re using non-FP languages (excluding Go and Lua) which can look weird if you start returning values.
This is a bit nuanced so I wanted to cover this core concept here so people clearly understand you can live in a programming world without unexpected runtime exceptions. Keyword there: “unexpected”. You can do this returning errors from functions instead of intentionally raising errors. Optionally, using sound types will get you to 100% of code, while not solving resource exhaustion exceptions.
The benefit to you? Your code is more predictable, you can release to production with more confidence, and you can deliver more features, faster.
You do this by treating errors as values; just like you return a string or number of discriminated union from a function, so too can you return an error instead of throwing/raising it.