Published on

How do errors evolve?

Authors

The last copy

Imagine that an unexpected event happened - the two evil villains, DDD (Database-Driven Design) and TDD (Table-Driven Development) did a vile act.

The world is in despair because of that.

Those two vicious anti-heroes wished for all of the people to forget how to properly model the domain, think about boundaries, assign responsibilities and use the language as a guideline.

All the copies of Blue Book are gone.

They destroyed both physical and digital ones.

Except one.

Seems like we need to protect this book from evil twins, DDD and TDD.

The Order of Hidden Sapphire

People want the knowledge, they seek the understanding.

Imagine that they around the world come to us to get a quote from the book.

This last copy is so valuable that we decided to keep it in a SecureSafe.

public sealed class SecureSafe
{

}
A secure safe

Its main responsibilities would be to ProtectTheBlueBook and to AllowAcessingTheBlueBook.

public interface IProtectTheBlueBook
{
    void Protect(BlueBook blueBook);
}

public interface IAllowAccessingTheBlueBook
{
    BlueBook AccessWith(PinCode pinCode);
}

Then we know how we can use SecureSafe:

public sealed class SecureSafe : 
                    IProtectTheBlueBook,
                    IAllowAccessingTheBlueBook
{
    public BlueBook AccessWith(PinCode pinCode)
    {
        //...
    }

    public void Protect(BlueBook blueBook)
    {
        //...
    }
}

(you might wonder why IUseInterfaces in a "strange" way - please look on I, interface)

To access the protected book, we need to type a PinCode.

public enum PinNumber {
    One = 1,
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9
}

public sealed record PinCode(IEnumerable<PinNumber> PinNumbers);

Then we can use BlueBook and fetch a quote from it.

Numbers, not letters

As our interface informs us, the expected input is a sequence of PinNumbers.

Only specified PinNumbers are allowed to be used.

When someone would even think about giving a bunch of letters, e.g. "admin123", it wouldn't make any sense.

// somewhere in a method...

safe.AccessWith("admin123");

In the code, our dear friend, the compilerm would give the feedback: cannot convert from 'string' to 'PinCode'.

And it makes sense - that's the designed interface.

This error (in thinking?) would be quickly revealed in the compile-time.

It is really precious gift to be able to check that things are correct in the compile-time. Instant feedback.

Of course, nothing stops a pesky and smart hacker to try to connect a device that allows typing sequences of both letters and numbers. It would be somehow translated to electrical signals that would try to break the PinCode.

// somewhere in a method...

SmartHackDevice
    .ConnectTo(safe)
    .AccessWith("hacking time!11!!" as object as PinCode);

The evil hacker might try as much as he can and nothing would stop him from giving input that no one designing the interface expected to get.

Still, all those trials are futile.

Valid numbers, not any numbers

It is really simple - someone designed the interface in the way that only numbers are allowed.

Things are different when it comes to validity of given PinCode.

One could stare at the pin pad and he or she wouldn't know what is the valid PinCode.

Someone needs to act, to run an experiment in order to verify or falsify the assumption.

Either the evil hacker gives the invalid input or we mistyped the valid PinCode, the feedback happens during the interaction with the pin pad.

Not before, while interacting with it.

We could name it as the "acting-time" feedback, but in fact we already have a name for it - run-time.

Imagine that given the wrong PinCode (doesn't matter how it got there), the SecureSafe would inform us about incorrect passpin (it's a not password as there are no letters 😉) by throwing an exception InvalidPasspinException.

Offtopic: making an implicit explicit

How would we know about InvalidPasspinException?

Where is it mentioned?

Documentation?

Should the moment of getting the feedback about this exception, obtained from docs reading, be named as reading-documentation-time?

Let's recall the interface:

public interface IAllowAccessingTheBlueBook
{
    BlueBook AccessWith(PinCode pinCode);
}

Hm, nothing is mentioned here about any possible issue with using it.

Is it only the run-time in which we can get this feedback?

In Essentially bounded, Accidentally unlimited, I concluded that:

Conclusion 🔍

There is no single solution, but there is a single problem.

Getting the feedback as soon as possible is the "problem" here.

Typically in C#, exceptions are used to inform about reaching failure-ish states.

Functional languages come with a beautiful "building block" named Result/Either (in F# we use the first one).

It has various interesting properties but one of its responsibilities might be to document various states in which the given collaborator might end up in. (you can read more here)

Some might say it's not idiomatic in languages like C# - are they afraid of The cost of modeling?

It's time to distribute the knowledge

Seems like our efforts paid off - many of the people got their quotes and domain modeling is preserved.

Imagine all of those interactions with people, chats, discussions, and so on.

Everyone would feel a bit tired. Overjoyed, but tired.

Other folks decided to evangelize domain-driven thinking but they needed quotes from the book too.

There's only one SecureSafe - what can we do?

It's very simple - we need to place the SecureSafe in one spot, and make sure that one knight of The Order Of Hidden Sapphire is available for a call so that he can serve a person doing the phone call with an answer.

Of course, it's questionable if we really need the SecureSafe right now. Someone protecting the resource would need to check the identity and permissions of the caller.

Nevermind, let's assume we made agreed with each other that we will use Verbal Phone Token (VPT), it's still based on PinCode.

Only the chosen, trustworthy ones know it.

Book, but deferred

Are we actually working with the SecureSafe right now?

Hard to say, as we don't see any physical object.

What about the interfaces we used to interact with the SecureSafe?

public interface IAllowAccessingTheBlueBook
{
    BlueBook AccessWith(PinCode pinCode);
}

The responsibility is exactly the same - but it's postponed in time, as need to call our friend.

Let's make the interface a little bit more closer to the truth - we want to document our intentions, right?

public interface IAllowAccessingTheBlueBook
{
    Task<BlueBook> AccessWith(PinCode pinCode);
}

Not a big change for us, though. Of course, we are not getting exact book, but it's software right?

Everything is possible in the software world.

We will make BlueBookQuote inheriting from BlueBook and override ToString method so that we can use existing model and not pay The cost of modeling.

Easy.

We could say that our phone would adhere to the interface IAllowAccessingTheBlueBook - but under the hood it will dial the right number so that we will get the quote.

Can you hear me?

Imagine that we are during a session in which spread the knowledge from the BlueBook.

We got a request to get a quote - we just need to call our friend.

Dialing...

Waiting...

"The person you are trying to reach is currently not available", the voice says.

Mother of God, not now.

We call him seven times in a row.

We send him a SMS. A voice message. An e-mail.

"I NEED A BOOK", one of them stated.

Nothing.

No response.

Available for a call, not a deferred book

We went further with our agenda and suddenly we got interrupted by excessive call-backs from our friend.

Ten text messages, seventeen e-mails, pictures.

What the hell is happening?

Turns out that our friend, having a guard in the remote, secure place, was having a trouble with serving all the requests he was getting.

All called him, sent messages and he was not able to handle all the load.

He decided to take a break from this stressful time.

When he got back, he started handling it again but unfortunately he was not able to do it right.

Not a compile-time, not a run-time?

When did we encounter the problems with reaching our friend?

We could say - in the run-time. As we would discover them while having an interaction.

We would experience it in that moment, yes, does it make any difference if our friend was located in the same building, but in the next room?

When we distributed the ability to get the knowledge from the BlueBook, suddenly we got new set of problems. (you might be interested in another aspect of distributing the responsibilities - Modularity Uncertainty Heuristic)

As we used phone call, sending SMS, and sending e-mails - we stepped into another dimension, where network is involved.

One then could say that the problems were revealed at network-time.

Distributing the knowledge in space (remote location) and time (network communication) isn't a matter of "fixing interfaces".

As moving between compile-time and run-time seems easy, moving between both of them to network-time, is a big leap.

Network-time errors involve another dimension that might materialize in the runtime, but it doesn't have to.

Network-time - what are other dimensions?

When hearing "The person you are trying to reach is currently not available" - the feedback is quite immediate - we need to try next time.

What would happen if we send an SMS - and there's no answer - did the recipient see it?

Should we send another one?

Distributing the caller and the callee, changing the way of their communicating, from direct call to message sending, might not materialize the issue in "run-time".

Of course, there are tools, methods, practices, patterns and principles (like Fallacies of distributed computing).

No doubt on that.

As compile-time errors and interprocess run-time errors are relatively easy to be encountered (and forced to occur), network-time ones require different mindset and perspective.

We spend some time on discussing the designed interfaces - how will it work when it comes to network-time errors?

Each of them involves a unique dimension, that requires analysis on its own.

Next time, dear Reader, when you would consider distributing any responsibility, ask yourself:

Question 🤔

What network-time errors am I introducing by doing so?