The mistake was not "explicit errors". It was having a mix of error types, some explicit and some implicit, with no convenient way to combine them, plus the interface complications.
Note that most newer languages are choosing explicit errors. This includes at least Go, Rust, Swift, Zig, and Odin.
The second mistake was only flirting with Bertrand Meyer’s work until the Gang of Four showed up and wrecked Java forever.
Meyer + functional core nets you a great deal of code with no exception declarations and an easy path for unit tests. If it hurts to do stuff it might not be the language that sucks, it might be you. Pain is information. Adapt.
There’s the Design By Contract work of course, but I’m still trying to cite what I thought was his best advice which is to separate decisions from execution, which is compatible with but I find to be subtler than the functional core pattern.
Often we mix glue code and IO code with our business logic, and that makes for tough testing situations. Especially in languages that allow parallel tests. If you fetch data in one function and act upon it in another, you have an easy imperative code structure that provides most of the benefits of Dependency Injection. Your stack traces are also half as deep, and aren’t crowded with objects calling themselves four times in a row before delegating.
if (this.shouldDoTheThing()) {
this.doTheThing();
}
Importantly with this, structure, growth in complexity of the yes/no decision doesn’t increase the complexity of the action code tests, and growth in glue code (auth headers, talking to multiple backends, etc) doesn’t increase the complexity of the logic tests.
A big part of scaling an application is finding ways to make complexity additive or logarithmic, rather than multiplicative. But people miss this because they start off with four tests checking it the wrong way, and it takes four tests to do it the right way. But then later it’s 6 vs 8, and then 8 vs 16, and then it’s straight to the moon after that.
> Remember that Eiffel, unlike other programming languages, is not just a programming language. Instead, it is a full life-cycle framework for software development. As a consequence, learning Eiffel implies learning the Eiffel Method and the Eiffel programming Language. Additionally, the Eiffel development environment EiffelStudio is specifically designed to support the method and language. So having an understanding of the method and language helps you to appreciate the capabilities and behavior of EiffelStudio.
I read "Object-Oriented Software Construction" to do so, but it was long enough ago that I googled "The Eiffel Programming Language" because my brain had substituted that title instead because IMHO, it's more accurate.
The above link should have many current resources for you.
Note that most newer languages are choosing explicit errors. This includes at least Go, Rust, Swift, Zig, and Odin.