What Makes good Quality Code?

What Makes good Quality Code?

There are a number of interesting comments in this thread about how to define quality code. I was reading through them and I think every single one of them could be summarized like this:

good quality code is code that make it easy for developers to add value

Every comment in there was some variation of this. There were many different approaches to how you can make code that does this. Some say you need unit tests. Some say it needs to be readable. Some say it needs good structure. Others say it needs to be designed to guide developers to do that right thing, and still others that it needs to be extensible. All of these seems to me like they might be good approaches to achieving the goal, but at the end of the day they all boil down to different theories on how to make code that enables developers to easily add value

I was thinking about this a bit and I think framing it in this way can actually help us come up with strategies for making good quality code. When we frame it in terms of making it easy to add value, it seems to me the next question is how does this particular code base add value? That of course pulls us into the business context the code operates in and supports. Thinking about that has a huge effect on what we would consider to be good quality code.

For example, I’ve written code that was not very well structured and modular before, but I would say it was still good quality code.  It saved me some time in writing reports, but it was code that was only for my use and it was small enough that I could remember what it did and easily tweak when I needed to. It was limited enough in it’s scope (and only had one user: me) that I could very easily test that it worked after changes. It was easy for me to add value with that code and since I was the only one who needed to change it, it was good quality code.

Now in many large scale systems with multiple developers working on it, the approaches I took to that script would have produced very low quality code (i.e code that made it hard for developers to add value). Understanding how your code is going to add value helps along to path towards figuring out how to make your code good quality.  I think when we start to divorce quality from value we end up in trouble.

Good quality code makes it easy to add value. How does the code you work on add value?  What things do you need to do to make sure it is easy for developers to continue to add (more) value?

Advertisements

Shipping Doesn’t Mean Done

Shipping Doesn’t Mean Done

Shipping doesn’t mean done. I read the phrase recently and it has been bouncing around in my head for while.

This is the mind shift that needs to take place for devops to be successful. There are so many definitions of done in software development, but we are used to the final arbiter of ‘doneness’ being shipping. We’ve shipped the feature so it’s done now whether we like it or not right?

Devops says no. Shipping does not mean done. It just means the feature is done enough to show to customers and get feedback on it. It means it is ready for the tweaking it is going to need in order to really add value.

If we don’t get this – and mean gut level get it, not just mental ascent get it – devops is going to be hard. For example: If your delivery schedule looks like this, you are probably still thinking of shipping as meaning done.

Untitled drawing (1)

The problem is devops doesn’t just mean the developers are on call when something goes wrong. It means the schedule should look more like this
Untitled drawing (2)

See? Shipping doesn’t mean done. There is so much value that we can add (as testers and developers) after shipping. If we don’t explicitly put that in the schedule, we are missing out on a lot of the benefits of devops.

And just to make sure I’m not putting too fine of a point on it, the key thing I’m talking about here is the schedule. If we don’t build that ‘after release’ time into the schedule, we are not going to be successful at devops.

When our team schedules look as if shipping means we are done, someone somewhere isn’t understanding or internalizing what we are trying to do in devops. We need to build time into the schedule for experimenting with and improving ‘in production’ features.  If we don’t do that we might as well just go back to waterfall, because then at least you are theoretically reducing the amount of buggy code you foist on your customers.

Don’t forget. Shipping doesn’t mean done!

API Testing is Exploratory Testing

API Testing is Exploratory Testing

Sometimes there are debates about what testing is and what words we should use when talking about aspects of it. I don’t worry myself too much about those kinds of debates, but there is something I have found to be true in my experience:  At it’s core, all testing is exploratory.  You can’t really find out interesting stuff about an piece of software without doing exploration.

This holds true, no matter what kind of testing you are doing. Sometimes when we hear about aspects of testing that require more technical skill we think they require less exploration, but I really don’t think so. For example, I have been doing a lot of API testing and am working on courses that involve teaching API testing. This testing has involved a lot of exploration!

There are a lot of tools that can help you with API testing, and I have been using many of them. Let me be clear though: using tools does not preclude exploration. I found numerous bugs in the APIs, but I didn’t do it by having a tool read in some swagger specification and hitting run. I did it by exploring. It seems like most API testing tools are focused on helping you set up automated regression tests. There is a place of regression testing, but don’t forget that these tools can also work quite well in helping you explore the API.

I was reflecting on the kinds of bugs I found during some recent API testing sessions and I found that they generally speaking fell into a few categories. I think these categories show how much API testing involves exploration.

Design choices

Many of the issues I found had to do with design choices. In many cases, the information we needed was in the API, but it was given to us in a way that was hard to use. This could be because it could only be accessed through API endpoints that were not relevant to the current context, or it could be because similar information was presented in inconsistent ways in different parts of the API. When it comes to creating an API (as with any software) there are many different ways to design it. Evaluating how effective the design of an API is at solving the problem you are working on is a thoroughly exploratory process.

Missing functionality

I also found issues in the API related to it not providing or respecting information the business domain required. This could show up in various ways. Sometimes certain object states were not being represented in the API.  Other times it was not respecting domain permissions correctly. There were also times when the API interacted with other aspects of the product in an incorrect way. Each of these kinds of issues required knowledge of the business needs along with current and desired functional requirements. It would be hard (or even impossible) to find issues like this without exploration

Algorithmic problems

Some of the problems found were more algorithmic in nature. Things like scores not summing up correctly in some instances, or issues like rounding errors. Issues like this could probably be found in more scripted (i.e. less exploratory) approaches, but even here we require a lot of exploration to build up an understanding of the properties of the system. For example, a property of the system might be that a set of scores should be summed to produce the total score, except if the user overrides the total score. You might know about this property through a business specification, but how do you know how this property is represented in the API? You have to investigate. You have to use the API to see how the various aspects of this are represented, before you are able to make any scripted check for the correct usage of this property. You also have to explore to figure out contexts that are relevant for this property. What kinds of things might cause this to be wrong? What kinds of variations are there in other properties that might influence this?  What kind of inputs could mess with this?  These are all exploratory questions.

Conclusion

So in conclusion I want to make this point: if you want to learn about API testing don’t focus in the first place on how to do the detailed automation workflows that the various API testing tools provide you.  Focus on figuring out how to find out crucial information about the API.  Where are the problems?  What does this API do? How will clients use it? What impact does the design have on helping solve the problem it was written for?  There are many things to consider when testing an API and I hope to get into more details in future posts, but for now I’ll leave you with this thought:

Don’t think of API testing as primarily a technical challenge.  Think of it as an exploration challenge.

Watchdog or Service Dog?

Watchdog or Service Dog?

Are you a watchdog?  I’m speaking to testers here. Are you a watchdog? Is it your job to keep a close eye on the code and product and make sure no bugs come through? What do you do when you see a bug? Do you start barking up a storm and waking everyone up? BUG, BUG, BUG. We need to fix it!  No bugs shall pass!

Or, are you a service dog? You watch out for pitfalls, and you help others navigate them.  You don’t just alert others to the presence of a bug, you help them figure out how to fix it and how to avoid it.  Do you do something about the problems you find that goes beyond just telling people about it?

I’ve called you a dog for long enough, so let’s step out of that analogy for a minute. What I’m getting at here is to have us step back and think for a minute about what a tester does. I’m asking a lot of questions in this article, and not really answering them because I want you to think about it.  Do we just provide information and raise the alarm when things go wrong? Or, can we do more? Are we willing to fix mistakes or is it only our job to report them?

Are you a watchdog, or do you provide more services than just a loud bark and the ability to spot problems? If you only think of yourself as providing information about when things have gone wrong, it will affect they way you work. How important is it to file bugs that you find for example? Are there other ways to deal with them? What do you spend your time on as a tester? These and many other questions have different answers if you think about who you are and what your role involves.  So how do you define yourself?

Are you a watchdog, or do you provide other services as well?

 

The Day I cut the Cord

The Day I cut the Cord

It was a pleasant Saturday evening.  I was just finishing up the first grass cut of the year and as I made the final pass by the edge of the house, the hum of the mower changed suddenly to a loud thwacking noise.  I quickly shut down the lawn mower to see what I had hit.

Uh oh.

It was the internet cable.

As I went inside to call my ISP, I instantly realized what a big role the internet plays in my life.  How do I find their number? Ah yes, I have a small data plan for my phone – I’ll use that to look it up.  After chatting on the phone with an agent, she asked if I would like confirmation for when they had someone available to come out for servicing it.  I replied with “sure just send me an email……” Only to realize that phone calls work better when one doesn’t have the internet.

We spent three days without the internet.  It was an enlightening experience. Life was harder in some ways – I mean we had to actually go look through our DVD’s when we wanted to watch something. No Netflix.  Also my wife runs an internet based business from home, so she had the schedule time in local coffee shops or visits with friend who had internet. Life was definitely harder in some ways.

But in some ways life was better without the internet. You know that little device in your pocket?  The one with a glowing screen and those addictive buzzes and beeps? Our data plan is small enough that we couldn’t really use it.  I would find myself pulling it out only to realize “No internet” and putting it back in my pocket again. Strangely enough I found other things to do.  Also strangely enough I still had friends when I didn’t respond instantly to messages and emails. Being free of the expectation to be responsive was enlightening. We all know we live in a world of instant, but sometimes taking just a tiny step back can give some perspective. Is instant <everything> better?

We are back online now, but we are taking and thinking about what it means to control this powerful tool called the internet.  We don’t give our kids butcher knives until they know something about knife safety, but it feel like we’ve just had the internet dumped on our laps and we’re still trying to figure out how to use this powerful tool without cutting off any fingers.

Our personal journey as a family towards using this tool effectively is one thing, but I want to end this article with a few reflections on how this translates into software testing. As a tester, you are in some ways a customer advocate, but let me ask you this question: Who is your customer?  Is the business or is the user of your product?  What if the the business concern of making money, comes in conflict with what it good for the users of your product?  Look at Facebook right now and you can see a bit of what I mean. Are algorithms that are designed to be addictive actually good for the consumer?  Of course you can argue that in the long run that they aren’t good for the business either – and I think it is a good argument – but who is pointing that out?  Who is looking at the bigger picture?

Testing can be a hard road to travel sometimes, but when I think about the ethics of testing, it involves thinking about tough questions like these. Are you working to make this world a better place?  I hope so. Let’s make this our mantra as testers:  “Making the world a better place, one dead bug at a time”. And don’t forget that sometimes that bug is a key feature in your product.

Do You Even Love Me?

Do You Even Love Me?

Have you even had a child put on their grumpy face, cross their arms and say something along the lines of “you don’t even love me”? Maybe you said no to them having more candy or insisted they need to do their homework before they can play video games or any of the millions of things that might upset a child.

The reality of course is that you do love them.  In fact, it is precisely because you love them that you are try to keep them healthy and make sure they are learning the things they need to know to be successful in life. They want something now, but you are looking at the bigger picture and you know that there is something better to be gained by giving up the immediate want.

Sometimes being customer focused can be like this.

Don’t get me wrong, I think the customer is ultimately the one who dictates the value of your software. If they don’t use it and find it valuable you aren’t really making good quality software, regardless of how well you’ve met the specifications. But sometimes customers ask for things and for you to be really customer focused you have to say no. Much like the parent who sees the bigger picture, you know things that your customers don’t.  You know the cyclomatic complexity of your code.  You know the state of your build system.  You know the risks that are there due to lack of test coverage.

Your customers don’t really care about that.  They just want the candy now, but you know what that candy will do to the health of your code. You know that you need to take that code to the gym and get a personal trainer to yell at it for a while first. Or maybe it’s even worse than that.  Maybe you need to call an ambulance and perform an emergency procedure.

Ok I’ll stop with the metaphors now, but the reality is that sometimes investing in underlying code quality issues is caring for the customer.  Sometimes slowing down a bit to clean up your processes is required to allow you move more quickly in the future.

There is a balance here of course.  The point still is to be customer focused and so you need to consider how healthy your code needs to be to meet those needs. The goal isn’t have code with a six pack, rippling abs and  a pearly white smile (sorry the metaphor is too fun – I had to come back to it).  The goal is to have code that is healthy enough to consistently deliver customer value.

As with your health, it’s a lot easier to do this if you make it a part of your regular routine.  It is a lot easier to stay healthy than it is to get healthy. Keep your code fit. Focus on the customer and make sure your code is able to help you do that. And the next time your customer asks ‘do you even love me?’ you can assure them that you do.  You are doing everything you can to have your code be around to help them out for as long as they need it. And if they’re patient, they might even get a lollipop.

Success and Failure

Success and Failure

I hate failure.  And not just in myself.  I don’t like watching others fail. It’s really hard for me to watch someone doing something ‘the wrong way’ without correcting them. As a parent I know I have to let my kids fail sometimes so that they can learn lessons I could never otherwise teach them. My son has been learning to read this year and as I sit with him and listen to him struggle with sounding out some simple words, I want to just read it for him. I want to take over and read it for him – it’s so much faster anyways. But I know that if I don’t let him struggle and fail I’ll actually be slowing down the learning process.

Work isn’t exempt from this.

How often have you jumped in to show someone what they were doing wrong or just taken over and done it for them? Or how many times have you stopped someone from making a mistake?  Sometimes it is a necessary thing to do, but have you ever short-circuited the learning process? I think that the idea of failure as something that leads to success is worth embracing.

If we leave it there though, we are in danger of missing an important point. Important lessons come from failure, but we need to set people up for success.

Now what gives on that? Have I given up on Aristolean logic? We need failure and success?

Yup.

You see to learn from failure, you need to be set up for success.  Let’s return to my son learning to read. He’s been setup for success.  He’s been taught what sounds letter usually make in combination with each other. He’s been taught some basic rules of reading and he gets feedback on what he is great at, as well as feedback on how to correctly say words he has messed up.  He has my finger under the word guiding him.  He has a teacher and parents that help him with this.  So do I let him fail? Yes of course, but only in a way that I think is setting him up for success.

I don’t want to see failure for failures sake. The goal is learning not failure and so the environment needs to be conducive to learning.  Learning from failure.

This blog is about testing.  Hopefully by now you have been able to draw a few conclusions on your own that can help you in the way you work with your teammates, but let me pull out a few of my observations as well.

How can you as a tester set up others for success? One time I was riding with a friend and we were coming up to a stop sign. Based on how fast we were going, I was pretty sure he didn’t see the stop sign. I quickly looked both ways and there were no cars coming on the cross road, so I waited. Then just as he was entering the intersection, I casually said “That’s a stop sign eh” (yes I am a Canadian). The look of panic on his face as he realized what he had just done was priceless, but why tell this story here? I want us to think for a minute about the key factor in there – I looked both ways.  I wanted to let him learn a lesson about paying attention that he wouldn’t soon forget, but what if there had been a car coming down the cross road? If I had let him smash up his car would I have been setting him up for success?  No of course not! The whole point of letting him run the stop sign was so that he wouldn’t do again sometime when it would be more dangerous.

Setting someone up for success means letting them fail in safe ways.  Letting a serious bug go live so that a developer can ‘learn to write better unit tests’ is not setting someone up for success. Working with your team to help them do more testing and putting together a transition plan that moves away from you being a safety net is setting them up for success.  There will be failures along the way of course, but you need to be doing everything you can to make sure everyone has the tools they need to use those failures as learning experiences.

Some other examples of setting yourself up for success in failure include things like shortening your release cycle so that you can better respond to failure.  A bug found in the wild? Being able to quickly respond gives you success in the failure.  Or another example is having instrumentation in place that helps you understand your customer’s pain points.  You could think of those pain points as failures in your design or code, but if you have set yourself up for success you can respond to them and learn from them. These are just a few examples, and I’m sure that if you think about it, you can come up with many other ways to succeed in failure.

So don’t be afraid of failure, focus instead on setting yourself and your team up to learn and grow from failures.