Deep Testing

When I was working on my API testing book, I noticed that the internet is broken.

The Internet is Broken?

Of course, the internet works just fine for many things, but in one particular way it is broken. The problem is, this broken piece of the internet is making it hard for you to advance in your career as a software tester.

We have long known in the software testing industry that testing skills are not usually taught within the traditional educational institutions. Instead we have managed to use the internet to learn. But what if the internet is broken? Then what do we do?

This article will be longer than most that I post on here. Partly because I think there is a lot to say on this subject, but also because one of the points I want to make is that shallow content isn’t always helpful. I want to explore this topic in a bit of detail. Stick with me and I’ll do my best to make this an interesting ride!

I want to look at this in 2 parts. First of all, I want to look at how and why the internet is broken. As we explore this, we will look at the history of filing cabinets (yes, you read that correctly), tool vendors, and of course social media.

Once we understand how the internet is broken we’ll turn to part 2 where we will look at some ways to fix it.

Part 1 – The Internet is Broken

As testers we often enjoy finding bugs. So maybe it’s not surprising to hear a software tester say the internet is broken. We’re always going on about how things are broken. Don’t just tune it out though. Let’s dig into a why I think this and then explore a few possible cause for it.

I’m a broken record when it comes to testing

How is it broken?

Before writing my book, I had done a lot of API testing and had even put together a couple of introductory level courses on API testing with various tools. I had a pretty good grasp of API testing. I had also used Postman quite a bit and so while not a world leading expert on software testing with Postman, I wasn’t a newbie either.

However, while writing the book, I had to do a lot of research. As I dug into things I realized that my knowledge of a lot of these things did not go very deep. And that is when I discovered that the internet was broken. I started searching for answers to some of the questions I was having, and they just weren’t there. This tweet might best sum up what happened:

All the search results kind of seemed the same. If I was looking to figure out that first surface level “Hello World” style of thing, the internet could give me all kinds of information. But if I was looking to deeply understand how authorization options worked in Postman, or if I wanted to know the nuances around different assert types, I would come up empty handed. More than once, I ended up reading through tests and source code to find the answers I was looking for.

I could find pages of results that would help me get started (although even then, for true beginners it’s pretty confusing), but it was very hard to find detailed information on a particular subject.

The internet had failed me.

Well actually, not really the internet. It was the search engines that were failing me. Let’s see if we can understand a little bit about why this was happening.

Why is it broken?

My dad was a pig farmer, and as farm kids, my brothers and I got really excited when he would take us to the pork producers convention. This was a trade show where various vendors would set up booths showcasing their products. As child I loved the free pens, stickers and candy they would hand out, but one part of the convention that I always found fascinating was a competition they had for inventions that different farmers had come up with.

Any farmer could submit their invention and have a display showing it off, and the attendees at the convention could vote for which one they thought was the best. Of course, part of the fun was to see if the invention that you voted for ended up winning. After a couple of years of following this part of the show I noticed a pattern. Every year without fail, the winning invention was incredibly simple. So simple in fact that you would almost feel like it wasn’t an invention. Of course, you would do that! The benefits were face-slappingly obvious to anyone in the industry. How could we ever have done it differently?

I think the filing cabinet was an invention like that.

The Filing Cabinet

The filing cabinet seems so simple and obvious that we probably don’t even think of it as an invention, but there was a time when they did not exist. Up until around the 1890s information was not stored in filing cabinets. However, it was an idea whose time had come and it soon swept across the business world. The filing cabinet allowed users to almost instantly find the papers they were looking for. No more thumbing through hundreds of pages in a ledger to find the entry you wanted. Now all you had to do was open the correctly labeled drawer and go to the folder you wanted and thumb through a few sheets of paper to find the one you were looking for.

But what does all this have to do with the broken internet? Well, as Craig Robertson argues in his book The Filing Cabinet: A Vertical History of Information the filing cabinet has influenced the way that we think about information. We think of it in terms of efficiency and indexing. It’s not the only way we think about information of course, but it certainly has coloured our view in a lot of ways, not least of which is in our search engines.

Indexing is a multi-billion dollar industry. Google makes it’s money by using software to index the world for us. It’s much faster and more efficient than the lowly filing cabinet, but it serves much the same purpose; allow users to almost instantly find the information they are looking for.

But isn’t that a good thing?

It sure is, if you are trying to find a certain piece of information. Forget about Google for a minute and jump back 100 years with me. Imagine going into an office building and asking a file clerk for information on how those newfangled Model T Fords are made. Thanks to the filing cabinet, the clerk can look up all kinds of things for you. They can quickly find the plans for the car, they can give you stats on how many were made and where they are getting sold. They can tell you all kinds of information, and get it to you quickly too.

You are now ready to create a company that displaces the Ford Motor company right?

Or maybe not.


Jump back into the present again with me. You want to learn how to be a software tester and so you ask your personal file clerk Google how to test software. You get back all kind of data. Blog posts. Tool vendors sites. Stats on how many testing jobs there are. Tutorials on using a tool. Opinions about testing.

You are now ready to be a successful software tester right?

Or perhaps, like the filing cabinet, indexed facts and data aren’t enough. Maybe the skills required to test software are a more complex puzzle then can be solved with a couple of hours of googling. Indexing prioritizes accessibility and speed over complexity and depth. The problem is successful software testing (and indeed all knowledge work) is complex and requires deep knowledge. When our primary information source de-prioritizes complexity and thoughtfulness – well you end up struggling to get the skills that you need.

Tool Vendors

In 1996 Bill Gate wrote an essay titled Content is King. It’s not quite what Bill Gates had in mind, but marketers have taken this to heart and now content marketing is a key pillar of many company’s marketing strategies. Combine that with search engine optimization and many tool vendor’s content can dominate the first page of Google results. This isn’t all bad and I don’t think there is anything wrong with tool vendors doing this. In fact, if done well, it can be a service to the community. I’ve written a few post for tools vendors myself.

The challenge is that this type of content – for very understandable reasons – is pushing you towards purchasing rather than learning. Again, nothing wrong with purchasing tools. Tools are a great way to help you get better at your job, but when content is created for “content marketing” purposes, it may not be helping you get to the kinds of depths that you need to be successful in your career as a software tester.

Social Media

And then there is social media. I think the “social media is destroying us all” horse has been beaten nearly to death, so I won’t go on about this too long, but it would be remiss of me to not mention this elephant in the room. Social media, being what it is, encourages silly debates and shallow engagement. It preys on emotional responses and doesn’t push us towards depth.

I don’t think I’m saying anything new or particularly insightful here (and certainly there are helpful things on social media), but if you are trying to figure out how to have a successful testing career, I don’t think the social media platforms hold the solution.

Part 2 – How to Fix the Problem

Ok, so anyone can complain about all the problems with the world, what about proposing some solutions? Problems like the ones I’ve mentioned above are systemic, cultural and large scale in nature, and so certainly there are no quick fixes for them, but I’ll share some steps that you can take that will help tip the scales in your favour as you seek to grow in your ability as a software tester.

Ground yourself in the basics

The internet encourages us to live in the never ending now. The latest news cycles or Twitter debates take our attention. We don’t have time to think about old things. Everything is always new. The tech industry has also continued to grow and expand dramatically which means that there are many new testers.

There are also a lot of new things to know about and use in testing. There was a time when UI test automation pretty much just consisted of figuring out how to use Selenium. Now we have a variety of UI automation tools that are all popular. We also expect testers to know about API testing. And how to use containers. And integrate with cloud platforms like AWS, Azure or GCP. And use cloud platforms like Sauce for cross browser testing. And accessibility testing. And don’t forget about security and monitoring and telemetry and performance and the list goes on and on. We have so much to know that it gets overwhelming and we end up just scratching the surface on all of these things.

All of these tools and ideas are wonderful and powerful, but we need a framework around them. We need to be able to understand which ones to use and when to use them. We need to understand why they might help us in solving the problems we face as testers. In order to get this, we need to also be grounded in the fundamentals of testing.

How do you decide what to test? How do you document what you’ve tested or are going to test? What are some test techniques you can use? How do you report on the testing that was done? How do you deal with the human part of the human/software relationship?

I was recently looking through my RSS feed and I noticed that many of the testing blogs I follow haven’t posted in a while.

Yes, I use RSS feeds

I went to some of them and tried to figure out what the blog owners were up to. Many of them have moved on to other positions. Managers or directors, or CTOs or stuff like that. It is great to see people moving up in their careers, but it made me feel a bit nostalgic. Maybe I’m just turning into a grumpy old man, but I kind of miss the days when it seemed that learning about basic elements of software testing was the cool thing to do.

There is a lot of richness and depth to the “basics” of software testing, and while we certainly shouldn’t fetishize them or dismiss new tools and ideas, we would do well to build on a solid foundation.

However, I think there is more to it than just learning the fundamentals. I think we need to contextualize them. If you read older books on software testing, they will sometimes use examples of things like testing dot matrix printers or drivers or even monitors and screens. The underlying fundamentals of how to think about and do good testing haven’t changed, but the ways in which the modern tester is required to put them into practice have!

We need to learn these without getting lost in the weeds of learning them in the abstract. There is a kind of person (I am such a person) who can get lost in the idea of things just because they are fun and interesting and learning about them is intellectually stimulating. That’s not what we need. We need testers who know how to test in the modern world of testing. This means we need testers that understand the fundamentals – but more than that – testers that understand how to apply these fundamentals in the daily work they are doing.

Fundamentals of Software Testing

So, what are the basics of software testing? I tried to map out what I thought they were, and the map got pretty big pretty quickly. There are a lot of concepts and ideas that relate to software testing! After a lot of wrestling with it, I distilled it down to the following list. At the most basic level I think we have:

  • Why test? – Understanding why we even invest in testing at all
  • What to test? – How to come up test ideas and how to do test planning and design
  • Communicating what you could test – How to write down test plans
  • How to test – How to actually go about questioning the product and evaluating the answers
  • Communicating what you did test – Test reports and bug reports

I think these boil down the basics of testing, but there are a lot of other pretty basic concepts to explore as well. These include things like different test techniques like boundary value analysis or risk based testing. There are also concepts like heuristics, oracles and mental models that are useful to be aware of when thinking about software testing. Then there are different software development methodologies, non-functional testing, and how to effectively use tools and automation.

As you can see, there is plenty to learn when it just comes to the basics of software testing. So in a world where the internet is broken how do you learn all of these things? Well, this in’t a blog on pedagogical methods, but one of my roles is to teach. I teach some testing courses and I am a homeschool dad, so I have thought about and paid attention to how people learn. I’m not an expert on these things, but I have a few suggestions that I hope will be helpful.

Try things

I am a firm believer in learning by doing. Learn a little bit about a concept I’ve listed above, and then try it out. Put it into practice and see how it works out for you. Until you try it and see where it is hard and where it works and where it doesn’t, you won’t really understand it.

Try things you aren’t ready to do

There is a bit of a chicken and egg problem when it comes to learning new testing skills. In order to learn the skills you need to do the testing work, but in order to do the testing work you need to have the skills. The way out of this dilemma is to do things you aren’t ready for yet. In order to get good at something, you have to first be bad at it. Part of learning by doing, is trying things before you feel ready for them. Don’t get in too deep over your head, but if you only stick to the things that feel comfortable you won’t make a lot of progress. You have to try things that you aren’t ready for yet and fail a few times.

I remember trying to write python code to automate some data generation that I wanted to do. I hadn’t been using python for long at that point and so I got stuck on something that I wanted to do (I don’t even remember what it was now), and I struggled with it for about a day. No matter how much searching I did, I still couldn’t figure it out. I asked some of my colleagues for help, but when I did the things they suggested, I didn’t really understand how it worked and so I would end up getting stuck again. I was in over my head, trying to learn something I wasn’t ready for and so I finally gave up and did the work the boring, slow manual way.

However, a few months later I need to do some similar data generation. With some trepidation I decided to try scripting it again. I ran into some of the same challenges, but this time I was able to figure them out and actually understood why things were working. The struggle of trying to do something that was “too hard” for me had helped me learn.

Longform Learning

Learning by trying is important, but you can’t go in too deep without having at least some grounding. I find the best way to learn is to try something out to figure out where my gaps are. Once I get stuck though it’s time to turn to learning some of the basics. I find that blog posts, articles and short videos (i.e. the things that come up in google searches) are helpful for filling some gaps, but eventually you need to figure out some of the foundations of a subject. Unless you don’t really care that much about getting good at it. If your goal is to just learn the subject at a surface level, Google results are fine. If you want to master a subject, or at least use it professionally, you need to go deeper then the first page of Google results. You need some longform learning

Books

Books are a great way to dig into a subject. Software testing has been around for a long time. Although the world has changed and software testing has (correctly) changed to accommodate it, there are still many foundational principles that you can learn from books. In fact, reading some older books can be a helpful learning exercise if you try to take the principles out of them and figure out how they can apply to the world of modern software testing.

So what books should you read? Well, asking this question made me realize I have some reading to do. I have a lot more books that I would like to read. Here are a couple of books that have been helpful to me on my learning journey:

These are books that deal with a lot of the basics of testing, but there are others that I would like to read as well. I was looking through my list of books that I’ve read and I realized that it has been over a year since I’ve read a book about testing or quality (The last one was Leading Quality since you wanted to know). I certainly don’t want to only read books about quality, but it’s time to get back on that train. Time to start working through my software testing wish list again.

Workshops and Training

There are a lot of free webinars and talks. Those can be helpful, but since we are talking about deep learning, you can probably predict that I’ll say they aren’t enough. A 40 minute talk can’t get you deep enough to dig into learning. Online courses can help you go a bit deeper, especially if they integrate a lot of activities (and you actually do those activities).

In depth learning takes time though. Half day or longer workshops and training sessions have a much better chance of taking you into deep learning than a one hour webinar or conference talk. This type of learning can get expensive, but if you are able to afford it (or to convince your company to pay for it), these things can help you get real depth into your learning journey.

Community

When learning is social it is much more fun. I preach this to myself. I have never been particularly good at keeping up relationships and community and it has only been to my own detriment. There are so many smart, talented and passionate testers. We need to feed off each other’s energy. There has been a lot of great work done around building community by the Ministry of Testing but whether you plug in there, or just find a few other passionate testers at your company to hang out with, community is a great way to invest in deep learning.

But I need to know for myself; how do you become a part of a learning community? Well, let’s think this through together.

Find the watering holes

Where do people hang out and talk about testing? Here’s a few places I’ve found:

Slack groups

I’ve found the slack group built around the AB Testing podcast to be a good place for community. It’s a moderately sized group (Under 1,000 currently) so it has a manageable post rate.

Another helpful slack group is the Ministry of Testing group. At close to 17,000 people, there can be a lot of posts. I actually stopped checking on it for a while because I found it overwhelming (Maybe its just my OCD around not leaving unread messages). It is a good place for building a learning community though, so I’m going to try again. I think I will look for sub-communities on there so that I can get to know some people with shared interests. Join me there. Let’s do this together.

Social Media

I know. I know. I just finished complaining about social media above. However, social media isn’t all bad. It can be used as a way to make new connections and to stay in touch with what others are up to. I find myself craving in person interaction though. Covid has been a long, long slog for me. It has been nice to be able to feel like I have a bit of an idea of what other testers are up to by seeing Twitter or LinkedIn posts, but as time has gone on, I’ve been craving in person interactions. I need to see my fellow testers in person. The passion and energy that drives us to learn and grow is best absorbed in person.

Conferences

So let’s talk about those in person interactions! Conferences are the best place I have found for that. I’ll be honest, unless you are able to go to an in depth workshop or tutorial, you probably won’t get a lot of deep learning from conference talks. However, that doesn’t mean that there is no value in conferences. I think that their real value comes from making connections with others that are passionate about creating good quality software. It comes in the hallway conversations and chats at the pub.

The difficulty is that conferences are expensive. Tickets alone can be expensive. Then you have to layer travel, accommodations and food on top of that. Plus, there is the time investment of going to a conference. As expensive as they are, if you can make it work I think the value is often worth it. As in person conferences open up again, I’m really hoping to go to a few. So far I have only booked to go to a local conference (KWSQA) which I will be speaking at. If you are going to be there let me know. I’d love to hang out!

Teaching

Speaking of speaking (how’s that for a phrase?), teaching others what you know is a great way to both build community and learn. I started blogging as a way to learn. Sharing my thoughts helps me learn. Blogging is also a way to be a part of the community of testers. I know blogging, speaking or other ways of teaching aren’t for everyone, but if you are up for it I would highly recommend it as a way to help you skew towards deep learning.

Short Form Learning

In an effort to contradict myself – a paradox makes me seem smarter right? – I want you to also do some short form reading. Yes, the internet is broken. Yes, it is indexed on shallow content. Yes, you won’t get far in building testing skills if you bounce around from search result to search result.

But that doesn’t mean these things are useless. If you have a particular topic you are trying to learn about, long form learning helps you dig into it. There is a downside to this kind of learning. You can get too influenced by a limited set of inputs. If you are trying to deeply learn something, it can be really helpful to expose yourself to a number of different perspectives and ideas.

Part of deep learning is spending some time doing a shallow survey of different ideas that are out there. I don’t want you to give up on blogs or following people on LinkedIn. Use the shallow nature of most internet content as a stimulant. Take the ideas you get exposed to and try to flesh them out on your own (maybe write your own blog post about them). Play around with the ideas you come across. Combine them with other ideas. Analyze them and reject them. Or accept them.

Use the shallows of the internet as a path into deeper learning and maybe we can save the internet.

Happy Testing!

Photo by Louis Hoang on Unsplash

How to Sabotage Quality: No Shortcuts

IN 1944 the organization that would later become the CIA sent a manual to their operatives working in the underground resistance in Europe. The manual was called the Simple Sabotage Field Manual. It contained advice on how people could quietly sabotage enemy operations. Let’s see what we can learn from it.

Much of it has to do with physical equipment, but for those of us in knowledge work the section on General Interference with Organizations and Production is instructive.

Insist on doing everything through “channels.” Never permit short-cuts to be taken in order to expedite decisions.

This is an interesting one for software testers to consider. Shortcuts can get a bad rap in our part of the industry. We tell people to do things the right way and to not take shortcuts in their design, development and testing.

But are all short-cuts bad? If a short-cut gets you to the desired outcome more quickly is it bad? Part of quality is consistency and some of the “channels” in our companies help keep things consistent. Sometimes shortcuts are bad, but if we never allow them, we won’t learn new and better ways to do things.

We don’t need to embrace “cowboy coding” but we can still have flexibility about how tightly we follow procedures. Part of producing good quality code is having the wisdom to know what kind of shortcuts will get you to the destination faster and which ones will leave you lost in the forest calling for help.

Don’t be the saboteur that insists that things always need to follow every detail of every procedure. Don’t just look at the piece you are working on. Look at the system and when you see a shortcut that works around inefficiencies in the system, don’t be scared to take it. Quality is as much a product of the system as it is of individual actions. Changes to the system can improve quality.

Photo by Stefan Steinbauer on Unsplash

My Personal Quality Principles

I’m joining a new team at work, and as I do so I’ve taken some time to reflect on how I want to contribute to the team. Obviously some of that will be specific to the context of the team I am on, but I’ve also decided to publish some of my personal quality principles. These are the principles that currently guide the approach I take to quality and testing.

  • Quality is a team sport. I don’t do all the testing. I might not even do most of the testing. My main goal is for the team to produce high quality software that makes customer’s lives better, and I believe that can only be accomplished if everyone on the team owns quality. This means that I will work with the team to make sure we are not cutting corners on the testing, and that we are all getting infected with the quality virus (don’t worry, it’s better for you than covid).
  • Testing should be an accelerant not a bottleneck.  This means that it should be rare or non-existent to be “waiting for testing to finish.” If testing is or becomes a bottleneck, I will work with the team to identify and mitigate the reasons it has become one. Time spent testing should be an investment in the future, not a form of evil that stops us from doing what we want.
  • Using testing as a safety net is an anti-pattern. Testing is not something that primarily happens after the code is written. Testing happens during design, during development and while code is in production. In other words, at every point in the software development lifecycle. Limiting testing to a just one step in the SDLC is inefficient and counterproductive. If the team is primarily relying on after-the-fact testing to stop them from getting hit by surprise bugs, I will do my best to help the team recognize and remove the need for a testing safety net.
  • People first. We write software so that we can make people’s lives better. If we are not doing that, we are making bad quality software. I want to know how our customer’s lives are being improved, which means knowing our customers needs and usage patterns. I love using telemetry and logging to understand the quality of our code, but we also need to remember that customers are fully rounded complex humans and not just data points. Alos, software is created by people, and so part of a people first approach to quality is to think about things that might impact the team. Software that makes the life of the team worse, is also bad quality software regardless of the impact it is having on customers.
  • Testing scalability is important.  Software development is all about scaling things. Testing needs to be done in a scalable way too. This means that I will work with the team invest in scalable test automation. Regression testing is too important to ignore, but particularly as a feature set grows, quickly becomes too slow to do manually.

Those are some of the principles that drive my approach to testing. The way that plays out in my day-to-day activities is, of course, going to vary widely depending on the needs of the team, but these are the goals and principles that lie behind the kinds of things I try to work on and advocate for.

Writing Words and Software

I have a problem when it comes to books. I want to read more than I have time to read. I’ve been able to mostly limit myself to just making insanely big Amazon wishlists, but sometimes I still can’t stop myself from buying books that “I’ll be sure to read soon.”

This has lead to a stack of unread books, and this year I’m trying to make that stack a bit smaller. One of the books I recently started reading from my backlog is T.E. Lawrence’s Seven Pillars of Wisdom. I’m not too far into the book yet, but in the introduction he talks about his process of writing it. He basically wrote the entire book from scratch 3 times along with numerous editing stages and re-works based on reviewer feedback.

The title itself came from another book that he wrote but decided not to publish because the considered it immature. Can you imagine having that kind of rigour going into what you write, before you publish it? We are used to having a fleeting thought and throwing it out there on Twitter for the world to see. I was struck by a thought and started pounding out this blog post. I’m certainly not going to spend 6 or 7 years working through different drafts of this and soliciting feedback before I put it out there for the world to see!

We live in different times and a tweet or blog post is a very different medium than a memoir style book, but have we gone too far? How much rigour and editing should we put into our public writing? What is the trade-off between getting something “out there” and making something good?

The internet is a medium the pushes us to one side of that balance. There is something about it that pushes us to publish our thoughts no matter how nascent or immature they might be – I feel it even as I type this post. How rare it is to pause even just for a few moments before we tap the send button. Taking 6 years to get our thoughts out there is incomprehensible.

I don’t think it is all bad, the push to publish. I’m publishing this blog post without taking a lot of time to review and get feedback. I certainly didn’t start it 6 years ago! However, we may do well to consider how the structures of the system we are in push us in certain ways. Are these ways all good? Could we be swinging the pendulum too far? Perhaps some between the extremes of 6 seconds and 6 years there is a sweet spot of thinking about the things that we publish to ensure that they actually will have a positive impacts on the world.

I’ve been talking about writing up until now, but if you take a moment to think about it, I think you’ll see the analogy to creating software. How much feedback and testing and thought should go into the software that we create before we publish it to the world? In software development, we aren’t generally trying to make something that will be an enduring classic that future generations will engage with 100 years from now, but are we really trying to make something that is an ephemeral as a tweet?

How much thought should go into the software that we publish? I think that if you look at social media platforms, you see a system that heavily rewards instant posting with little to no thought. I don’t know about you, but I find social media to be less and less helpful (although there are islands of usefulness in it). In software development we have a those that espouse code changes going live as quickly as possible. In doing so are we pushing our software systems to become as raw, unmediated and fickle as Twitter and Facebook? Are they going to become more like social media over time?

Let me clarify a few things. First of all, there are some great ways that I have seen people use social media. For example, it can be used as a way to test ideas and get some broad exposure to different ideas very quickly. If you are looking to grow and learn your ideas, social media platforms can be effective for that. The same applies to rapid releases of software development. If the point is to see if your idea is valid, or to better understand some different perspectives that you might be missing, getting your code out there as quickly as possible is a good idea.

If the point of sending your post out into the world is to get as many likes as possible, it seems much less likely to me that your are using the platform to do good in the world. The same with rapid releases of software changes. If the point is get your code out there so that you can have as many dollars as possible, it seems less likely to me that you are actually releasing in a way that is doing good in the world. Rapid releases are a useful tool, if used for the right thing; learning and growth.

A second thing. I am not advocating here for some form of long slow release process. In fact I think having the ability to nearly instantly release code to the public is an enormous advantage. What I’m advocating for here is that we use these kinds of things with thoughtfulness. Just because we can, doesn’t always mean we always should. Sometimes a tweet is the right thing, but sometime a blog post is better and sometimes you need to sit down and write an entire book.

Sometimes immediately releasing your code is the right thing to do, but sometimes a bit of patience and polishing pays off. Sometimes a long slow release pays off. But even then, consider T.E. Lawrence’s process for “releasing” his book.

He wrote the first draft and then lost most of it at a train station (Lesson: always use version control). He then rewrote it into a second draft, but with this draft he was just trying to get down as much as possible of the details before he forgot them. He made sure it was as accurate as possible, but in his words it was “hopelessly bad as a text.” (Lesson: create a prototype). He then wrote a third draft based on the accuracy and structure of the second, but written with much more care (Lesson: Learn from, but don’t ship the prototype). He then sent 5 copies of this text to friends of his for critical review (Lesson: Even things you think are good, can be improved by external feedback). He then incorporated that feedback into the final version of the book.

Overall Lesson: even when releasing something that needs more time and polish before going out, getting feedback along the way is important.

To pull this back to software development, if you are trying to release something that is good quality you will need to have learning loops in place. Testing up front is one such learning loop, but external feedback loops are important too. Just be careful to use that external feedback as a learning loop and not just as a way to feel good about having “released” something. In a world of rapid releasing, live code does not mean you are done. Done happens when you’ve made something that is making life better, not necessarily when you’ve shipped. Shipping is just an experiment. Make sure to treat it as such.

I’m hopeful for humanity. We have things like social media that have been around for a while, and we are starting to figure out their pitfalls. It has taken us as a species a bit of time to figure out this new medium. It doesn’t work like a book or even a blog post and so we can’t put the kind of trust in a post on LinkedIn or Facebook that you can in those other forms of writing. I think we are starting to figure that out and I’m hopeful that we will continue to get better at understanding how to use these platforms well.

In the same way, we have moved to shorter and shorter release cycles in software development, but we haven’t fully adjusted to the new world yet. We still sometimes think of those releases the way we thought of those big bang, year-long releases that we used to do. I think we are starting to get it though. A release is an experiment not a final state.

The more we learn the better we get. Keep on learning!

Photo by Raphael Schaller on Unsplash

Broken People; Broken Software

This world is a broken place. I recently read an article in my local newspaper about parents who lost their son to a drug overdose. The article was posted on Facebook and to read through the comments was hearwrenching. There were several other parents from my town that posted about how the healthcare system had failed them and their families and how they too had lost children to mental health and addictions.

When I read something like that I start to wonder. There is so much brokeness and hurt in our world. There are so many systems that are broken and we are all struggling in our own ways, but what am I doing to help? I have my comfortable life doing my comfortable job, but am I really making a difference? Is this world a better place because of what I do? Am I clawing back at the brokeness at least in some tiny way?

The answer is supposed to be, that by helping get better software into the world, I’m making a difference, and I suppose that is true. But we’ve all felt the weight of the current cultural momen that we are in. Is it enough?

I know I’m not responsible to solve the world’s problem. I know I can’t do it on my own. I know there will always be more that can be done, but how do I connect my work to something more? I don’t talk about it much on this blog, but I am a religious person, and so I do believe that we have a purpose in being here. We were made to do something. Part of that is to make this world a better place.

I’m not ready to give up this thing I love called software testing. I find it facinating. I love what I do and I want to keep doing it.

I just want to comit myself again to doing it with purpose.

I don’t do this to just move up in my career or to make more money. I do this to make life better for a few people. I do this because it brings me joy, and helps make me a better person. I do this because it’s a way to shake my fist at the darkness and brokeness in the world. I do this to cast a glimmer of light. Maybe together we can make a million glimmers of light and change something.

I want to see a world where people aren’t annoyed by software bugs, but also a world where software improves people’s lives. I don’t just want to ensure that we build it in the right way, but also that we build the right thing.

I don’t want to just find bugs (although I do still want to do that). I want to promote ethical software. I want to help people find their own meaning and fun in testing. I want to see us get better at making sofware that acutally enhances people’s lives. Not just better adoption or more users or even higher customer satisfaction ratings. Software that truly makes lives better.

Some of the brokeness in this world comes from software and if we testers won’t take the time to point it out who will? It time to shift the culture of tech. It’s time to stop treating humans like they are data points in our algorithims and instead start treating them like, I don’t know, complex beings with thought, desires, loves and hates. It’s time to do something different.

I don’t know – maybe this article is just therapy for me, but I want to see something different. I don’t know exactly what that is yet, but it’s time to explore it.

Photo by Marianna Smiley on Unsplash

Queuing Theory and Testing

Just for fun, I was recently reading about queuing theory (that’s a normal thing people do for fun right?). One of the things that you need to think about in queuing theory is scheduling policy. There are a number of different way that you can pick which object in the queue goes next. One scheduling policy that intuitively makes sense to me in the first-in, first-out policy. Basically, you would pick the thing that has been in the queue the longest as the one that goes next.

But you can also choose to use a last-in, first-out policy. That doesn’t seem very fair to me. Think about waiting in a queue at the grocery store. You’ve been in line for a while, and someone else comes along and stands behind you in line, but when the next chashier is ready, they help the person who joined the line after you. The last one to join the line is the first one out. Why would you ever choose this scheduling policy?

Well, since I was just reading this for fun, I didn’t bother myself about it too much, but then a couple of days later it hit me that we often use a variation of this policy in the way we manage our backlogs. Things that have been recently added to the backlog are more likely to be worked on than things that have been there for a long time.

Why is that?

One reason for it might be availability bias. The newest items added to the backlog are fresh in our minds and so they seem to be more important. This is a bias, but since software is built by humans, for other humans, it might not be so bad to have human biases in the decisions. Things that are fresh in our minds are probably fresh because they are related to new features that we were working on. These things might be ok to work on first as they might be fresh in our clients minds too. Of course, we should still at least give a little bit of thought to that before assuming it is true in every particular situation, but it might not be an all bad thing.

Another reason for using this kind of queue scheduling is that it might be cheaper to work on stuff that is fresh rather than having to get back into an old context. If we have just created the story or filled out the details on a defect, we should have a pretty good understanding of what we need to do for it. This can mean that we can more quickly complete the newer work in the backlog than we can the older.

I don’t want to gloss over a glaring reality though. The last-in, first-out policy means that those poor items at the front of the queue are very unlikely to ever get a turn. Since there is always more work to be done than there are people available to do it, without some other mechanism to bubble up those older tickets they will languish forever. Most teams have mechanisms that do this (even if they are not deliberately put in place). For example, a client might escalate a known issues and hence bump it up in the queue.

But can we be more intentional about them? What do you think? What are your strategies for dealing with those old defects or stories that have been in backlog for years?

I’m an Author?

I love learning new things. One of the reasons I started this blog was so that I could capture some of the things I’ve learned, but also so that I could learn more effectively. I have always found that for me one of the best ways to learn is by explaining the thing I’m learning to others. Blogging has allowed me to hone and deepen my thinking on a lot of things related to testing.

In the last couple of years I have also branched out into learning and teaching with video courses. I’ve made courses on a number of different testing related topics, and in the process of doing that have been able to learn a lot.

Last year Packt Publishing approached me about writing a book on API testing with Postman. I had published a video course about this with them previously, but writing a book is a lot of work so I said I would have to decline. However, after thinking about it a bit more and discussing it with my manager, we worked out an agreement where I would be able to go down to 4 days a week at work so that I would have the time to work on the book.

Writing a book!

I have to say, writing a book really is a LOT of work. I was already fairly familiar with Postman and API testing, but in the course of writing the book I found I had to really dive deep into some areas. When you dive deep into something you start to discover that there is a lot that you don’t know yet. I had to learn new things and struggle through fundamental concepts. I wanted to make sure that I understood what was going on at a deep level so that I could clearly and simply explain it in the book.

I also spent a lot of time coming up with practical examples. Things that the readers can do on their own. Books are great. I read 3 or 4 books a month and I think books are probably the biggest bang for your buck that you can get when it comes to learning. However, as the ancient Greek philosoper Epictetus said “Books are the training weights of the mind. They are very helpful, but it would be a bad mistake to suppose that one has made progress simply by having internalized their contents.” You can’t just read a book and think that you know the subject. You need to internalize it’s contents. With technical books like this one, I think that is best done by working through the subject on your own. To that end, I have numerous challenges and worked examples that help the readers internalize what they are learning.

Writing a book was certainly a tough and challenging endeavor, but it was also a helpful part of my ongoing quest to be a life-long learner. I learned a lot, and I find myself working on some new things at work that come directly out of the things that I learned. I hope that if you read the book, you find that you are able to learn a lot too!

Free Copies?!

I’ve not only been learning new things about API testing, I’ve also been learning about how book publishing works. One of the things that is important with new books is to get some reviews. In light of that, the publisher has a few free copies available in exchange for your honest review of the book. If you are interested in that, feel free to reach out to me on twitter, or LinkedIn or feel free to send me an email at davewesterveld@gmail.com and I’ll see if I can get you a free copy.

The book is called API Testing and Development with Postman and it is coming out on May 7th (2021). If you do pick it up, let me know what you think! I hope it is helpful.

I guess in a way I have been an author for a long time. I’ve been blogging for many years, and I have published a lot of video courses, but there is something about writing a book that makes me feel like I can now actually call myself an author. Damion Synadinos, has a talk called More Than That, where he talks about the different ways that we label ourselves. Well, I feel like now I have applied a new label to myself. I’m an author.

I guess I better go update my LinkedIn profile.

Photo by Aaron Burden on Unsplash

New Post on TestProject Blog

I know I haven’t been writing on here much lately, but if you are looking to read something I wrote, check out my latest post on the TestProject blog.

It’s about getting started with their open source Java SDK. I like learning new things and this was a fun way for me to learn a bit more about Java!

As I say in that post

 When you have a powerful tool, you don’t need to avoid it. Rather, you need to learn how to wield it well.

It was fun diving in to learn how to better use that tool. Check out the full post here.

Creating Schema for an API

From the outside, software development and magic are indistinguishable. Of course, with enough time you can understand how it works and for those of us who have made it through the frustration of learning to code, it’s really not all that magical after all. It’s just the application of a few simple rules.

I kind of felt that way about schema. I’d heard the term before and I had seen errors come up in my code editor saying that I had a schema validation error. As far as could tell though this all came about by some sort of magic. Well, it turns out this kind of magic can also be learned.

In my last blog post, I wrote about what it was like getting started with creating an Open API specification. In that post, I glossed over the part about creating a schema for the API. However, that was actually the hardest part of getting started with Open API for me. I realized that I didn’t really know that much about schema and how testers can use it. If you too are in that boat, I hope this article will help you out a bit!

What is an API Schema?

Well, when it comes to API schema, we are talking about a set of rules that dictate what the API request or response is allowed to look like. Creating an API schema is about finding the patterns in what the API does and creating rules that define those patterns.

At this point you might still be a bit confused and thinking “give me something concrete.” Well who am I to argue with you on this? When the people ask for concrete examples they get them, even if the people are only made up voices in my head.

Suppose you were looking at an API that gives you data about COVID cases in your country. One of the fields in the API response is the number of cases. You know some things about this field. For example, I’m pretty sure you can’t have less than 0 COVID cases (unfortunately). I’m also pretty sure you can’t have partial cases of covid. This means that you know that this field needs to be an integer that is greater than or equal to 0. These are some rules that you can apply to that field in your API response. What an API schema does is gives you a way to encode and document these rules.

How Does Open API use Schema?

Open API uses the JSON Schema as it’s starting point. It doesn’t use all the elements of JSON Schema and it does add some of it’s own elements as well, although the latest 3.1 Open API spec has pretty much synchronized the two. You can define the schema in a couple of ways. You can just do it directly inline with the resource you are trying to define, or you can create it in a shared schema section in the specification file and refer to it from the resource. I will show you an example of the second way of doing it.

In the previous post, I showed an example of defining an endpoint that looked like this:

paths:
  /endpoint/path/{pathParameter}:
    get:
      description: Makes the world a better place.
      responses:
        '200':
          description: You got a totally ok result.
       content:
            application/vnd.siren+json:
              schema:
                $ref: '#/components/schemas/SchemaName'

The $ref: part points to where it should be getting the schem from. You can create that section in the specification file and then add your schema into it.

components:
  schemas:
    SchemaName:

In this section you can then create the rules that you want to enforce. I have found the documentation on this page to be helpful with figuring out how to create the schema rules that I want. If you consider the example of an endpoint that should only have positive integers, you could specify the schema for it like this:

components:
  schemas:
    SchemaName:
      type: integer
      minimum: 1

By referencing this schema in a response, you would be saying that htis response can only contain integers that are 1 or more. There are of course, many other rules that you might want to specify in a schema, and you can see some great examples in the documentation I referenced above.

I know this is a very quick survey through the subject, but hopefully it helps you to get a grasp on what a schema is and on how and why you would want to use one in an Open API Specification.

Photo by Ivan Aleksic on Unsplash

Getting started with the Open API Specification

Twenty, twenty-one, twenty-two. Twenty-two seconds! Twenty-two seconds to load the data for a simple table. Somehow we had repeated the same mistake we had run into before. A year or two before we were working with an API that used sperate endpoints for each cell in the table we were creating on the page. That works fine until you have a table with 100 rows and 5 or 6 columns. Now you have to send hundreds of API calls and even if each one is small on it’s own, it takes time for the calls to traverse the network. The HTTP protocol limits the number of calls you can make concurrently and so queing theory applies and the load time for the table gets really slow.

And now here we were. We were creating another table in our UI and the API that supplied it had a different endpoint for each cell in the table. How did we get here? During the design we had discussed performance and how we would need to design the API so that we wouldn’t come across this exact issue. Somehow as a team when we go caught up in the work of creating the APIs that would pull together all the data we needed, we missed this piece of the API design.

We are a well functioning, highly productive software development team. In fact, we refactored the API to work as it should have within a week, and yet we had missed this. I suspect we aren’t the only team that has faced something like this. We were building a system that would deal with a lot of complexity and present it in a simple way so that our clients wouldn’t need to deal with it. The challenge of course, is that there are so many details to keep in mind. Domain and functional requirements. Design and presentation of the UI. Security and correct user permissions. Accessibility and performance. It isn’t possible to keep this all our heads at the same time. Thing get missed.

That’s why we have testers right?

I don’t know. That doesn’t feel like the right approach to me. Sure, we can use after-the-fact testing to find those bugs, but we had already identified this bug. We knew that creating an API where each cell in a table needs to call a different endpoint is not scalable. In essence, we had to find this bug twice. Once during design and once after development. The second time we found it, the bug was expensive to fix. Could we have prevented that regression? Can we create regression tests for our designs?

This is one of the problems that API specifications attempt to solve. In reflecting on this issue, I started to wonder if we could have saved ourselves a lot of rework by encoding the things we had discussed and discovered during our design sessions. What if we wrote them down in an API definition that set out what the API should look like and do?

You can’t do much about the past, but you can learn lessons from it and use those lessons to make the future better. I’m sure our team will be writing more APIs in the future and so I want to explore some of the different API specification to see if there is something that would make sense for us to use in the future.

Open API Specification

The most common specification format is the Open API Specification (or OAS). It has in many ways become the default specification for describing how APIs work. It has very broad adoption across many companies and has a large supporting community. It is designed for RESTful APIs, which we use, and it has support for almost anything you would do with these APIs.

I’ll be honest though, I find it overwhelming to get started with. It is a lot of work to document every detail of what your API can or should do. Since we have existing APIs that do not yet have API definitions I thought I would try using the Swagger inspector. It gave me something to get me started, but it still needed a lot to be done by hand. Since at this point, my goal is more around evaluating if this makes sense for future APIs, I decided to instead look at creating a definition “from scratch”. I’d like to use a design first rather than code first approach to this.

So how hard is it to create an API defintion that follows the OpenAPI Specification?

The Tools

Well, let’s start with talking about the tools. There are a lot of Swagger tools that work with Open API Specifications. Confusingly the OAS used to be called Swagger, but once you get past that, there are still many tools out there. It’s easy to get lost in trying to figure out which tool does what, and which one you want to use. I know because I spent too much time trying to figure out which one to use. Eventually I decided that I wouldn’t use any of the custom built tools. OpenAPI defintions are just text files (either yaml or json format) and so they can be edited in any text editor.

I created a file in my trusty Visual Studio Code, installed a couple of OpenAPI formatting and linting extentions and I was finally off the races. I’m sure that if I use this more, I will eventually want tools that are built specificially for the OAS, but I’ll stick with the basics for now and see where the pain points show up as I scale. If you are new to using the OpenAPI Spec, I’d recomend taking this approach too. Not only will it force you to understand what is going on more deeply, but it will also remove a whole layer of confusion that can get in the way of just getting started.

Creating the API Defintion file

A blank file staring at you can be intimidating, but I guess the best way to get something done is to start doing it, so let’s look at what data needs to go into this file.

The First Section

So, how do you actually create an API definition with the OAS? The basics of it are straigtforward. Start with a bit of boilerplate at the top that says what version of the OpenAPI Spec you are using along with some information about the API your are creating the definition for.

openapi: 3.0.1
info:
  title: A cool API
  description: This API does cool stuff
  version: '1.0'
servers:
  - url: https://{tenantId}.domain.api.com
    variables:
      tenantId:
        default: tenant-id-guid-123

One simple thing I ran into here was that each instance that we create (and we have at least one for each of our clients) has a different base url. This includes all the testing sites. Pretty easy to take care of though. You can create a parameter in the url. You can read more about how the base urls work here if you want.

Defining an Endpoint

With the boiler-plate out of the way, the next thing to define is an endpoint. Endpoints are defined under the paths section.

paths:
  /endpoint/path/{pathParameter}:
    get:
      description: Makes the world a better place.
      responses:
        '200':
          description: You got a totally ok result.
      parameters:
        - name: pathParameter
          in: path
          required: true
          schema:
            type: integer
            format: int64
            minimum: 6606

I’m obviously redacting some stuff here, since these are internal APIs, but it’s interesting to note how easy it is to create a parameter in the path. All I needed to do was to include it in the path defition and then create a parameters section under the request to define what kind of parameter it was.

You will notice though, that the responses object only defines the response code. It says nothing about what kind of content this API should give back. That seems like it would be kind of important. Defining this opens up a whole new can of worms. Obviously the API does not always give back an identical response every time you call it, and so you can’t just copy a response and put in in there. Instead you need to specify some general rules that should apply to the response. For example, you could specify that it should be a list and that each item in the list should be a string. These kinds of rules are known as schema. The kinds of objects our API represents are pretty complex and so it takes a bit of work to create a schema for them.

In fact, as I dug into this I realized that this is actually the area that was the most intimidating to me. I’m pretty comfortable with the way RESTful APIs work and so setting up stuff with the paths was pretty intuitive. However, although I have benefited greatly from using schema that other have made to help with validation, I have not had to create schema before. I did find a good schema generation tool here that really helped, but I needed to go through and do a lot of clean up. Everything that went into creating the schema is worthy of it’s own blog post someday, so I won’t go down that rabbit trail right now.

After creating the schema, I could use it to define how the content of the response should look:

paths:
  /endpoint/path/{pathParameter}:
    get:
      description: Makes the world a better place.
      responses:
        '200':
          description: You got a totally ok result.
       content:
            application/vnd.siren+json:
              schema:
                $ref: '#/components/schemas/SchemaName'

In the content object I’ve first defined the content type. This is what is returned in the Content-Type header of the response. I then use a $ref object to specify a reference location where it should look for the schema for this response. Schema is often shared between different parts of an API, and so by moving it into it’s own section, you can reference it from multiple places without needing to create it multiple times.

Defining Security

As I said earlier, I won’t get into the details of creating the schema in this post. Instead let’s look at how to define security options. The API I’m investigating uses bearer tokens which is pretty easy to define with the OAS.

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
security:
  - bearerAuth: []

And with that, I have an extremely basic, but functional schema. I’ll leave it there for now, but in future posts I will share how it went when I was creating a schema and also share how I used the definition file to actually do something useful.

Although it was a bit intimidating at first, as I worked my way throught this, it didn’t take long to feel like I could put together something useful. How did you find it getting started with using the Open API Specification?

Photo by Jon Eric Marababol on Unsplash