There may be no new problems, and yet, we do our level best to try and create them. It's often said that what we do as software developers is hard. **What we do isn't hard. How we chose to go about what we do, that's what makes it difficult to do. If a task is difficult, it's not necessarily because the task is intrinsically difficult. There are several items to check off first:

Do I understand the problem (have I sufficiently broken it down)?

Have I attained sufficient competency to both practice my craft generally and in a specific context?

In the law, when an issue is analyzed, we determine whether there are threshold issues that must be first addressed. For example, if you slip and fall in a store, can you recover damages? That depends on whether the shopkeeper was negligent. Negligence depends on whether the shopkeeper had a duty to a foreseeable plaintiff to exercise reasonable care. If reasonable care was exercised, that settles the matter. The issue of damages is irrelevant.

Software development is no different in that we need to always break things down to their constituent parts. In other contexts, we call this root-cause analysis. In other contexts, we employ what is known as the scientific method. We learn by observation and testing. From that, empirical data is produced that provides the evidence for us to be able to make informed decisions. Whether we, in fact, make informed decisions, depends on whether we follow the evidence and whether we respect the science. That's the irony of our industry. Logic and reason are at its core. But too often, those two things are the first casualty of problem solving. The scientific method, in one form or another, traces its roots back many thousands of years: i.e., principles endure.

There are many phrases we employ today that convey these meanings: What's past is prologue and Those who forget the past are condemned to repeat it. These quotes are attributed to William Shakespeare and George Santayana, respectively.

Whether it be politics, foreign relations, domestic policy, human nature, etc., the lesson is clear; although there may be some new and novel aspect to any individual thing, taken all together, the problem has been encountered before. Take COVID-19 as an example. The analog used to understand it is 100 years old: the 1918 flu pandemic. That's not to say that the two are the same. They're not. But there are many similarities and, at a root level, the same core issues faced in 1918-19 are what's being faced today. It may very well be that what's being faced today is more serious than what was faced in 1918. That, however, is a different issue, one of scale.

Another way to illustrate the point is by way of fiction writing. Christopher Booker's 2004 book “The Seven Basic Plots” sets forth that proposition in a very straight-forward way. The seven basic plots are:

  • Overcoming the monster
  • Rags to riches
  • Tragedy
  • Comedy
  • The quest
  • Voyage and return
  • Rebirth

In fact, we can break these down further to rising and falling. Sometimes the story is one or the other. And sometimes it's a combination of the two, multiple times in different sequences. For all the twists and turns and factual differences, when we break them all down in a coding project, there are only a few categories that we end up with. Any software does at least one and up to four things: create, retrieve, update, and delete data.

Whether 50 years ago or today, we have problems to address with technical solutions. To do that, we write, test, and deploy code. That's what we do. At a foundational level, software creates, retrieves, updates, and deletes data. These are the CRUD operations and that is what the software does. How the software does what it does, that's indeed different. Where we used to rely exclusively on relational databases and SQL, today we may rely on NOSQL and unstructured solutions. Very different things, to be sure. But at a fundamental level, we're talking about the same thing: key value pairs. That's what JSON is. That's what XML is. And yet often, JSON is regarded as a newer, more modern thing and XML is regarded as old. In .NET Core and VS Code, we have the appsettings.json file. It's just a configuration file, like app.config or the ini files we employed in days past. They're different things and, at the same time, the same things. What's the threshold issue? It's context.

Another phrase that comes to mind is: **The only constant is change. It seems like a paradox: On one hand, things are the same; on the other hand, they're different. The contradiction can be resolved if context is considered. On one hand, being a Luddite isn't good. On the other hand, technical churn that's always in the favor of what is perceived as being the latest and greatest isn't good either. To be the greatest at anything implies that there's empirical evidence to support that. New things, by their very nature, lack empirical evidence. That's why we should always test first. Another quote for the pile: Trust but verify.

Wisdom: Where Knowledge Meets Experience

It's important not to confuse the use case with the actual problem. For example, the need for a new daily sales report isn't the problem; it's a feature request. There are many subordinate issues that need to be addressed to achieve this goal. At its core, the request is about data retrieval, which, in turn, has (among other things) rendering, performance, and security concerns. As we bore into the details, we eventually realize that for each thing we encounter, there's a solution that's been employed before. One question is how far into the weeds we need to go to break the problem down to its constituent parts. There's no precise answer. The generic answer is to dig as deep as is necessary and no deeper. What does that mean? It means that you keep digging until you hit familiar territory.

If, after digging for a while, nothing is familiar or isn't understood, look in the mirror. You may lack the necessary experience to deal with the issue. You need the wisdom to know when you don't know. And if you don't possess it, collaborate with someone who does. Anything else and you're just burning cycles with no benefit. This is where a culture of collaboration and inclusiveness matters. No one person has all the answers. And yet there are those among us who seem to instinctively know how to break down and solve problems. In other words, there are those who know that boiling the ocean is an exercise in futility. Knowledge comes from learning, not instinct. Those of us who have the knowledge and experience have a moral, ethical, and professional obligation to share it so that we can pass it on, because once upon a time, somebody helped us. That isn't enough, though. Organizations and leadership have their roles to play as well. They must foster a collaborative culture. There's a responsibility to lift people up. It's one thing to talk. It's another thing to walk it and live the sermon.

It's not enough to have people who are willing to teach. There needs to be an environment that is conducive to giving people the opportunity to learn. It's not about top down vs. bottom up. It's about meeting in the middle. If it sounds like liberal democracy, that's because that's precisely what successful organizations practice. And by doing so, they avail themselves of the ability to take advantage of wisdom its personnel have.

Read Showstopper!

In 1993, an amazing piece of software was finally available to the public: Windows NT. NT was comprised of millions of lines of code amongst 40K files, written by a team of about 250 people over a period of about four years. As somebody who was an early NT adopter, I remember well the fanfare for its release. At the time, I knew nothing of what it took to build NT. As it turns out, it took many things: money, careers, egos, mental health, marriages, etc. That is what the book “Showstopper! The Breakneck Race to Create Windows NT and the Next Generation at Microsoft” by G. Pascal Zachary is all about. I profess that it's been in my library for quite some time, but I just finished reading it. Originally published in 1994, it's a book I wish I'd read years before. It's the kind of book that's worthy of many readings during your career.

My biggest takeaway from the book is the reinforcement that there are no new problems and that the past is just a prologue. There are lots of great insights into the challenges of managing large teams, complex features, and testing. What makes Showstopper such a poignant read is how it focuses on the one individual who led the NT team and his journey as a developer that started in the early 1960s. As of today, David Cutler is nearly 80 and is still a distinguished technical fellow at Microsoft. Here is a somewhat recent article from 2016 that highlights Cutler's and his cohorts' history:

Never Stop Learning

This is not the same thing as being on the hamster wheel of technical churn where we trot out and deploy new things for the sake of it! I've lost track of my own past efforts to learn enough about something just to realize that it's better to leave it on the shelf, never to be touched again! The issue is the never-ending quest to somehow leverage the good without encountering the not-so-good. How do we keep control of a large project and, at the same time, keep control of what today we call the work-life balance? In striking the balance, how do we decrease defects (showstoppers), increase features, and increase delivery velocity? The very first words in the Agile Manifesto that codified principles 19 years ago says it best:

We are uncovering better ways of developing software by doing it and helping others do it.

The challenges faced by the NT team were no different from those faced by other teams, and the Showstopper book provides insights into how the team confronted what were many serious issues. NT leadership (specifically Cutler himself) recognized the propriety of testing by non-developers. That was, to a large degree, a very ego-driven personality who set aside his ego for the benefit of the project that was a creation of his vision and realized by his drive.

Eight years after NT was released, 17 notable and famous software developers met at the Snowbird Resort in Utah to craft the Agile Manifesto and its supporting principles. We're still trying to figure it out 19 years later! How do we learn? By doing. In other words, we practice the craft, and in that regard, what software developers do is no different from what any other professional does. Practice implies skills development and continuous learning. We learn by doing and our feedback loop is empirical data. In my opinion, good developers take the time to understand and appreciate history, and then they learn from those experiences and go on from there.

Delivery is a feature. We can't analyze a problem to death. We must be pragmatic. We must avoid perfection becoming the enemy of progress. That's not a license to just throw something over the wall for the sake of delivery. Tools and techniques come and go, but principles endure. That was the gist of my technical article on Unit Testing in VS Code (in this issue). VS Code is quite different from Visual Studio. If you take on VS Code with Visual Studio expectations, you'll flounder. On the other hand, if you consider, at an abstract level, what you're trying to accomplish, and apply testing principles; principles that transcend specific tools, there's no longer an impedance mismatch between context and your mode of problem solving. The solution will make its presence known and will just fall into place. And if it doesn't, it's time to cut bait and consider a change in approach. Often, that change requires a refined problem definition, a better understanding of the problem, or a better understanding of the tooling, just to name three possibilities. How things work as they do is subordinate to why things work as they do. When you focus on why, you necessarily will focus on base principles.

Why do base principles always apply? Because principles endure. And why is that? Because there are no new problems.