Test Your Understanding
Human communication is complicated.
Using words to express ideas is so fundamental to the way we operate, the amount of effort going into it is often overlooked. Learning to communicate effectively is one of the more important skills for software professionals (and anyone) when working in teams.
Every time we try to communicate something verbally with one another, we go through a complex protocol of establishing a connection and making sure we have the attention of our counterpart before beginning to speak. There are a series of handshake processes and initializations in the communication channel.
We say hello (or something that means the same thing) to each other and, in some cultures, ask questions without caring about the answer. There have been lamentations over asking “how are you?” when there is never an honest answer—just a stock “fine” and a lack of concern over the true condition of the other person.
Despite the seemingly wasteful and silly nature of this exchange, there is a purpose to it. By exchanging these “pleasantries,” the communication channel is established and confirmed.
Even after we know we have a sound communication channel, we test its continued integrity via checks and confirmation of understanding. We ask “Are you still there?” while on the phone, and things like that.
This is not that different from how internet communication happens. It should not come as any surprise that machine communications protocols designed by humans mimic human communications customs. In fact, the Simple Mail Transfer Protocol (SMTP), includes a command called HELO (a four-letter form of “Hello” since SMTP commands are four characters) that initiates communication and identifies the sender to the receiver.
Network communications are modeled after human communications.
Human communications are often unreliable.
Network Communications as a Model for Human Communications
When Peter Deutsch and his collaborators articulated the famous “Fallacies of Distributed Computing,” the first item in the list was: “The network is reliable.” Calling this a fallacy is a simple statement of a simple truth:
The communication channel is not always reliable. This is as true of human communication as it is of network reliability.
Ensuring communication continues is important.
Most communication on the Internet is done via Transmission Control Protocol (TCP). Typically, programmers are familiar with the idea that in a layered model of internet protocols, an application layer protocol like Hypertext Transfer Protocol (HTTP) rides on top of a transport layer protocol like TCP.
TCP is like its sibling, User Datagram Protocol (UDP), in many ways. The main difference is reliability. TCP has guarantees regarding the delivery of information packets (or at least surfacing a failure to communicate) not available with UDP. This is because TCP operates via a process involving sending information and waiting for an acknowledgement to confirm the information was received.
UDP is a simpler and more performant form of communication than TCP. It does not have all the overhead and packet acknowledgement that make TCP reliable. Communication via UDP is like making a speech without concern for whether the listener actually hears and understands it. Information is just sent with the hope it reaches its destination, but without confirmation.
UDP is faster because it requires less communication back and forth, but it is less reliable. Packets can be lost when delivered via UDP and the sender is unaware they were never received. Sometimes this is an appropriate and an effective way to communicate. Usually, making certain the message was received is worth the overhead of reliable communications.
Reliability comes at a cost. Reliable communication requires continually testing the channel and looking for acknowledgement of message delivery.
UDP is often used in things like streaming media where speed is of the utmost importance, and the show goes on if some packets are lost here and there (though usually with noticeable communications artifacts).
TCP is used when speed matters, but reliability matters more.
And reliability almost always matters more than speed. It typically does you little to no good to use a high-performance communication channel that loses some or all of your message and leaves you unaware of the loss.
Human communication works best with a model more like TCP than UDP. Speaking to a coworker only makes sense if you have cues indicating that you have their attention and receive a response. Responding when someone speaks is not only a matter of courtesy and manners, it’s essential to effective communication.
Like internet software favors TCP over UDP for most needs, humans favor reliable communication to just talking without checking for connection.
Programmers are like Children
I recently interviewed Aslak Hellesøy, the creator of the open-source Behavior-Driven Development tool, Cucumber, on my podcast. He shared what he called “an epiphany,” and I immediately agreed that what he articulated was profound and insightful.
This piece of the conversation, coming from Aslak, is at the 35:19-37:04 mark of the show.
“I had this epiphany in the shower this morning when I was thinking about this podcast. I don’t know if it’s a good metaphor, but a lot of teams focus a lot on testing the software—It’s important to test your software but it’s even more important, I think, to test your understanding of what you are going to build. I think a lot of people don’t actually test their understanding. People who have kids do this. I have a 3-year-old daughter and her language skills are good enough now that after I give her an instruction I can ask her to repeat it back to me, so I can test her understanding. Sometimes she will tell me back what I want to hear and other times she will tell me something else which means the test failed and I have to explain it again. I don’t know why people don’t do this more in organizations that buy or deliver software. It’s just mind-boggling to me.”
Consider speaking with a child. With good reason, we tend to put less trust in the communication channel with children than we do with adults. We tend to ask more questions concerning the recipient’s understanding of the information.
We know that inexperienced recipients have a higher probability of misunderstanding.
Parents and other teachers of younglings need to be patient. Communication takes longer with more testing of understanding to verify receipt and understanding in exactly the same way that using TCP is less performant than using UDP.
This cost is incurred without remorse because of its great benefit and its obvious necessity.
Software professionals tend to have great expertise in ways to build systems and a widely varying degree of expertise in the business domains for which they build software.
Explaining a business concept to a person who may or may not know anything about the business domain is a minefield fraught with peril. The risk of misunderstanding is enormous.
In order to demonstrate understanding, it is necessary to repeat the idea, concept, instruction, or other type of message in the words of the recipient and in such a way that a shared understanding is established with the sender.
Aslak is correct—it’s like instructing a child.
Teams building software needs to test their understanding of the domain problem and the expectations of stakeholders in the same way parents and children need to test the effectiveness of their communication.
Effectively Communicating Intent for a Software Product
A dump of requirements into a document by the hand of a business analyst is not good enough. Teams require the expertise of multiple roles to construct examples in order to specify what is expected.
Matt Wynne and Aslak Hellesøy, in The Cucumber Book, described a gathering a three distinct roles that make up the expertise of the team. This collaboration of “The Three Amigos” (the developer, the quality professional, and the domain expert) form a backdrop for successfully understanding needs.
The intent of “requirements gathering” in software is to understand the intended value of the system and to guide design, testing, and implementation in such a way that the system fulfills the promise and vision of those for whom it will make something easier, faster, better, or possible.
Fleshing out an understanding of the problem domain and driving toward asking questions about why something is useful is the first step in trying to understand what should be delivered.
The main thrusts of these practices are explicit and effective communication. The most important and central premise of DDD is to get everyone on the team, technical and nontechnical alike, speaking the same language regarding the domain. The idea and value of BDD is using examples to describe and understand the problem space.
Treat software requirements/specifications/stories as you would teaching a child (though probably from the perspective of the child). You need to test your understanding and that of everyone on the team. As UDP packets can be lost into the ether(net), so can communication among humans.
Treat the information regarding the problem domain you receive from domain experts the way a web server treats TCP packets—by sending an acknowledgement that includes a statement of the information in your words.
Nuts and Bolts—Steps for Executing Tests of Understanding
If you start working on a system for handling the operation of a library, there are several things you need to do to test your understanding of the domain of the problem.
Communicate in the terms used to describe the domain.
Do the domain experts talk about checkouts or loans? If the library loans books, compact discs, Blu-rays, and ebooks, how do the domain experts talk about the items that can be used? You need to use those terms in your conversations, documentation, specifications, tests, and code.
Communicate understanding back to the domain expert(s) in words understood by both technical and nontechnical team members.
Instead of talking about the library website users getting a 200 Status Code on HTTP requests to the server or seeing unordered lists on a web page, talk about expectations for viewing the status of loaned (or checked-out, depending on the vocabulary used by the domain experts) items.
Question assumptions and approach the problem from a different perspective.
When you are told there needs to be Optical Character Recognition (OCR) on book covers as they are returned to the library, understand you are being given a solution, and not the problem.
Ask questions and get the domain experts to explain the problem they are trying to solve instead of just implementing their solution. There may be a better one. They want to identify the item being returned. Reading a bar code might work better.
Collaboratively construct and document examples demonstrating the desired behavior of the proposed system.
Talk with domain experts about what happens when Joey, a 13-year-old student with five monetary units in outstanding fines on his account, borrows Harry Potter and the Chamber of Secrets as a paperback book and returns it 33 days later.
Use those documented behaviors as tests for the correctness and utility of the system.
Using examples to create executable specifications that verify the system works as intended is an excellent practice. Gojko Adzic’s book is a great resource for this. Try Bridging the Communication Gap: Specification by Example and Agile Acceptance Testing to learn more.
Implement enough of the system to get feedback and acceptance from the domain experts and real users.
Instead of approaching the technical aspect of a project, like building out a service layer, implement a piece of functionality, like borrowing an ebook. Get this in the hands of real users as soon as you can.
Continue to refine the shared understanding and language of the domain with developers, testers, and domain experts.
As you learn more about the problem and run into the complications when implementing the solution in the real world, continue to have conversations.
Update your model where it makes sense. When you realize you have more than books to loan, use a term that is more inclusive, except in those cases specific to books.
Final Admonition to Test Your Understanding
Do not trust that you know what is needed without understanding the domain. Do not trust that you know what is needed without asking questions. Do not trust that you know what is needed without iterating on a problem and getting frequent feedback.
When you interact with domain experts, you need to repeat their ideas about the domain in your own way, but with the terms they use to describe the domain. Use your own style, but make sure you are not reinventing necessary words to describe the domain. Domain terms form part of the ubiquitous language with which all team members can communicate.
Express your understanding so that it can be clear with those involved. Instead of saying, “Yes, I understand,” say, “What I heard you say is…” That’s a great formulation for affirming what someone else communicated and clearing up possible misunderstandings.
Testing your domain understanding frequently by utilizing domain experts is the most impactful and effective way of asking the right questions and delivering the right software.