Published on

The Inverse Matrix problem

Authors

Refactoring

Imagine that there's a development team and their day started as usual - a typical daily meeting, each team member contributes to the mass illusion of doing Agile (we release every quarter), all staring at Jira.

Tasks dispatched, workers...I mean, engineers assigned - the whole production can start working!

Days passed and Mary got a notification that her peer, Rick, assigned her to perform a code review (as we all know, it's about the code as it's the most important thing, right?).

Mary had completely no idea about the conceptual advancement that the reviewed PR introduces, as there are 37 files touched.

She went through one file by one file and suddenly spotted a change that checked a bunch of ifs, throwing exceptions here and there.

It was hard to get the context of this PR; the conditions seemed reasonable, but the lack of tests didn't provide enough understanding of the rules behind.

And those exceptions.

Imagine they decided to have a quick sync about this PR, using a video call.

Discussion
Rick, a developer: Yo, what's up? Mary, a developer: Hi! We're doing code review, as you assigned us. Can we have a bunch of questions? Rick, a developer: Sure! Did you like the decorator pattern? It's quite clever - now we can... Mary, a developer: Why do you throw an exception in line 9872? Seems like it is a regular step in the process. Shouldn't we notify an operator instead? Rick, a developer: Good question. I actually didn't know what to do, so decided to throw an exception. I think front-end guys will figure out if they want to show a fancy spinner or other UI-esque thing. Mary, a developer: Hmm, but the process should continue, just another path? Rick, a developer: Yes, path - if the condition is not met, we enter inside the if body.

Mary requested changes, but PR was merged anyway, as there was a demo in the next day, and product owner couldn't wait more.

After a couple of days, someone couldn't continue with the process as "Sorry, please try again" message started popping up, with a nice, flashy UI.

A new feature

Next sprint planning just finished.

Motivated team was ready to brainstorm new features.

Discussions were mostly about new possible 3rd packages needed (both NuGet and npm), along with necessary infrastructure changes.

We had a great time, as we all love to discuss technical stuff.

Suddenly, one of the team members, Mary, raised a question. Rick and Henry participated in the discussion.

The debate was related to User class.

Discussion
Mary, a developer: Guys, I don't think we should add more properties to User class. Rick, a developer: Why? Didn't you pay attention to UI? Wallet, number of tenders, email - it was all there. Henry, a developer: Personally, I don't like to have too many classes - there's more to understand. I fear spaghetti code. Mary, a developer: Product Owner clearly stated that tenders might grow pretty fast, especially when tenders are tiny. Wouldn't that impact database? Henry, a developer: I don't know - I just want to have it in the single place - it's easier to reason about. And remember Mary, we are going to maintain that. Rick, a developer: What's more, recently we added connected traders to User and nothing bad happened. Henry, a developer: See, another good point to keep it in the single place.

In six months and many more properties added to User, the team suffered from performance issues, which they tried to cure with scaling up and out.

But what's worse - the team was constantly fixing bugs related to User class, as it was hard to understand all the implications of changes.

A bug

The same team struggled with a critical bug in production.

The bug was related to a tendering process - some users were not able to place tenders.

A tiny discussion started in the team chat.

Discussion
Rick, a developer: Don't worry guys, I know this area of the system. This will be an easy fix. Mary, a developer: I hope it won't be in a User class... Henry, a developer: You should just place if after this statement (shows with a mouse). Rick, a developer: Yeah, exactly. But we need to make another call to a database. Hmmm Mary, a developer: What if this is not the right place for this if? Rick, a developer: Pardon? What do we mean "not the right place"? Henry, a developer: Look - there are other ifs around, so it seems it's the right place. Mary, a developer: But those other ifs are related to user profile and e-mail being correct, not about tendering. Henry, a developer: Sorry, but we don't have time right now. I'll put a ticket for it.

After quick fix was deployed, more ifs started popping up in the code, as more and more edge cases were discovered.

Soon, the team was overwhelmed with bugs, as the code became hard to understand and change.

And the mantra was "just add another if".

An improvement

The brave team gathered again - during sprint planning - ready to take another challenge.

Yet again, it was related to tendering process - according to Product Owner, there was another step required, after it was completed.

Discussion
Rick, a developer: Seems like we need another status in the Tender class - Verification? Mary, a developer: But we didn't ask why it is required at all? Henry, a developer: Well, Product Owner told us so it's our job to do it, isn't it? Rick, a developer: I think we need to create AggregateRoot base class and let User inherit it - our job is to keep tendering consistent according to rules. Henry, a developer: AggregateRoot? What is that? Rick, a developer: It's a design pattern that comes from Domain-Driven Design - basically you expose methods on your classes and keep logic there. Mary, a developer: User class contains much more information than we need to maintain consistency for tendering process, isn't it? Henry, a developer: I really would like to keep User as it is - it allows easier reasoning for related database tables. Rick, a developer: I am good with that, as long as we use AggregateRoot pattern - it will help maintaining consistency. Mary, a developer: I am not quite sure if...

Eventually, AggregateRoot was introduced, with User inheriting it.

User class attracted more and more logic, and it turned into a benovelent dictator of the system.

Soon, developers became hostages of User class, as it was hard to change anything without breaking something.

THE code

How do you feel, dear Reader?

I hope you feel those situations are pretty exaggerated and such things don't happen in real life.

Or maybe you can relate to them?

It is quite typical that we, software engineers, focus on code, as it's the most tangible thing we have.

Even though it is pretty virtual, this is the most "tangible" thing many interact with.

Slicing, merging, reviewing, moving, deleting, copying, pasting, committing, breaking - we do a lot of things with code.

Code is our material we work on.

Sometimes it might seem that there's nothing else but code.

We even get called "coders".

Some might even say that our job is solely about writing code and to get paid for that.

In a way, code constructs our identity, as software engineers.

Matrix

Have you seen "the Matrix" movie?

If you didn't, I highly recommend watching it.

Here's a little spoiler (or a main point, if you wish): people lived there, unaware that the reality was a deep and advanced simulation.

And the true reality was quite different.

Pretty grim and dystopian, where human beings were bred and used as an energy source by machines.

One time the main character, Neo, started seeing beyond the reality he knew and understood that the world was nothing more than "a code".

Literally, code.

the "reality" in Matrix

All his gestures, all actions, all dreams, senses - everything were just a software construct, until he "woke up", and saw the true reality.

During and after watching the first movie out of three parts, one might start questioning the symbols, the reality, and the true nature of things.

What was the significant event that happened was looking beyond the current "reality", which turned out to be a mass illusion.

The Inverse Matrix problem

One could say that people living in Matrix had a big problem - they were trapped in an illusion that prevented them from seeing the harsh truth of their existence.

What if "coders" are also trapped, but in an alternative way?

We convinced ourselves (by various means) that code is the most important thing, the only thing that matters.

It is our "reality".

"The code" covers something truly important, something that really impacts what we do and why we do it.

Matrix "realities": perceived, actual, hidden

"The code as reality" manifests as characters on the screen - "it's just an if", "it's just a class", "it's just a service".

We are really good at deceiving ourselves (in general, as human beings, but here we refer to "coders") with "code" being the most important thing, reinforcing the illusion.

Believing that tools can solve all our problems with existing code, we employ BDDs, DDDs, ATDDs, Design Patterns, and so on.

But the magic is that there is no magic (and be aware that Tools make fools?).

Are we overlooking the "true reality" of our work?

What if we are all trapped in the "Inverse Matrix"?

We see "the code" as our "reality", but in reality there is much more: there are people, processes, drivers, goals, culture, and so on.

Remember: we build Systems: by, with, for people.

There are areas for which our efforts are supposed to provide solutions.

Most often those solutions are related to artifacts like "executable code", but it shouldn't neglect people using and benefitting from our systems, processes that are supported to make other people work/lives easier and culture in which we operate while organizing ourselves.

Inverse Matrix "realities": perceived, actual, hidden

Often, "hidden reality" depicted above could be understood as "sociotechnical system", where "people and machines" exist together, interact with each other and co-evolve.

Only when interactions happen, there is a probability that an expected behavior will emerge, leading to providing the value.

But is there anything we can do to escape the "Inverse Matrix"?

(you can, dear Reader, think about a related question: why one might want to escape the "Inverse Matrix"?)

Escaping the Inverse Matrix?

Turns out that might be quite simple, but not easy (when I say "easy", I mean "requiring low/no effort").

Don't rush to writing code.

Don't envision the solution right away.

Start with questions.

Slow down and build the context.

Who is going to use this piece of information?

How is it going to be used?

Who is paying for it?

What is the expected behavior?

What does someone want to accomplish?

And collaborate - involve others, share your assumptions, and seek to understand.

Techniques, approaches and methods like Strategic Domain-Driven Design (in general: looking beyond code, visualizing the knowledge and understanding) can be a really good first step into a beautiful journey, full of traps and ambiguities, but also full of discoveries and learning.

What business capabilities are required to provide a necessary level of service?

"Ah, but I am not a business analyst or an architect!", one might say.

Even though one might not have a specific job title, we still can train ourselves in asking questions, building shared context.

"Yeah, but it will be slower this way - asking those questions, collaborating, etc.?", another might comment.

Yeah, it will be slower for sure - but what is the goal?

As someone said: "we always can build the wrong thing quickly".

Let's visualize "escaping the Inverse Matrix".

Imagine that as we got trapped in a frame of being "coders", we put a special "glasses" on our noses, that distort the perception by filtering out everything, except the code.

It framed ourselves in "thinking in code", rather the business areas, people, processes, business capabilities.

Our job is to "take the glasses off" and start seeing bigger picture.

Metaphorical representation of escaping the Inverse Matrix

And especially in the time when "AI" is becoming more and more prevalent, focusing only on "the code" might be a trap, as "AI" can generate code for us - but can it synethesize understanding?

Free yourself from the "Inverse Matrix".

Next time, dear Reader, when you start working on something, vocalize a question:

Question 🤔

Is there something I don't see as the code covers it?

Take the glasses off.