I'm a big fan of testing. I write about it on my blog, I email my mailing list about it, I discuss it with other developers in my spare time, and I have even gone as far as creating a course that teaches testing with Go.
Despite having a fondness for testing, I don't recommend it for beginners.
Crazy, right? In this article I plan to explore why that is in a little more detail, but it basically boils down to two points:
- Beginners don't know enough to write anything but the most trivial tests. This inevitably leads to my second point...
- Trying to learn the skills required to actually write realistic tests while also trying to learn how to code and build things is overwhelming.
I guess it is kinda one point. Whatever. I'm breaking it up into two because I think it makes it a little easier to consume.
I know many of you may not agree with me at this point, but please give the article an honest read. If after reading it all you don't agree I'm happy to discuss it with you. After all, I'm here to learn as well 🙃
This article was original posted on calhoun.io, where I write about Go, web dev, testing, and more.
Beginners don't know enough to write anything but the most trivial of tests
Whenever a beginner writes code their primary goal isn't to separate concerns, avoid global variables, or to write testable code. Honestly, most beginners probably don't know what half of those things really mean. Instead, their primary goal is simple; it is to get the damn thing to work. That's it.
Confirming this hardly takes any effort. Take some time to review some code written by beginners.
Looking at a web app written in Go? Chances are they are writing SQL queries anywhere and everywhere in that code, and theres a pretty good chance that their DB connection is a global variable.
Looking at a Rails app? Chances are there is business logic in the views and the controllers have tons of logic jam packed into them.
Looking at a PHP web app? It wouldn't shock me if ALL of the logic is in a single php file - parsing a form, interacting with the DB, etc.
Even if we look at something simpler - say a calculator with limited functionality - we are still going to run into issues like this. It isn't that beginners don't care; they simply don't know any better.
Beginners don't know what dependency injection is. They don't understand how global variables make testing hard. They probably don't even know what mocking is, so expecting them to understand how to design code that is easily mocked is quite the stretch.
As a result, the only tests that really make sense to a beginner are the really simple ones like below.
func Add(a, b int) int {
return a+b
}
// And a test...
func TestAdd(t *testing.T) {
got := Add(2, 4)
want := 6
if got != want {
t.Errorf("Add() = %d; want %d", got, want)
}
}
While I don't have any problem with showing this to a beginner and giving them an idea of what testing is, I think it is pretty ridiculous to show them this code and pretend that it is anything like a real test.
So what ultimately ends up happening is we try to teach them more. We try to teach them what dependency injection is, why global variables make it hard to test, how time.Now()
can make it hard to verify edge cases, and more. And this is where I start to get worried, because we are no longer teaching a beginner how to program. At this point, we are teaching them how to program, how to build things, AND HOW TO TEST all at the same time. And that brings me to my second point...
Trying to learn the skills required to actually write realistic tests while also trying to learn how to code and build things is overwhelming
Like before, I want you to think about code written by a beginner, but this time I want you to recall some of the first programs you wrote. Think about the first thing you made that was composed of more than one source file. Or maybe think about the first web page you made.
Now if you were anything like me, your first web app might have looked something like this:
<p>
<?php
// This may not work. I don't know PHP anymore.
$name = $_GET['name'];
echo "Hello, " . $name;
?>
</p>
A work of art, isn't it?
Now imagine if you just managed to write that code for the first time and someone told you that you should be testing your code. And you should be using React. And you should be using a framework. Oh and you will want to setup a database, and probably setup GraphQL to query it.
I'm not sure why, but as developers we have this habit of taking what we do now - after years of experience and practice - and expecting others, especially beginners, to be doing the same things right away. It is ridiculous. It is like expecting someone to be able to jump right into calculus just because we learned trig, algebra, and more which eventually lead to us learning and using calculus to solve a particular problem.
Just because something works well for you, doesn't mean it is a good idea for beginners. They might not have the context, the experience, or the practice required to really benefit from what you are using. Or maybe the problems they are tackling are just much simpler, and tossing in all that complexity is overkill.
It's like we all forgot that we gradually learned how HTTP request work. How headers work. How cookies work. How forms work. How POSTing to a web server works - or even that there ARE different HTTP methods. And through all of this we probably learned through some good old fashioned trial-and-error.
I don't actually think testing is at fault here, but the real problem is that we have this stigma that you should learn how to code, testing, web development, and a million other things all at the same time. I don't really know how this came to be, but I suspect part of the issue is that we never qualify things. A beginner asks, "what should I learn?" and we tell them, "learn testing, and react, and graphql, and go, but only use the standard library..."
No, no, no! Just stop.
This is ridiculous to me because of how obvious it is in any other scenario. If you were teaching someone how to play soccer you would start off with the basics like how to pass and how to dribble. You wouldn't start them off with videos of Ronaldo and say, "This is how the professionals do it." So why the hell are we doing this with programming beginners?
We try to make it better by saying, "well of course they should know not to try to learn that all at once", but they don't! And what makes this even worse is that when budding developers fall into this trap it leads to them feeling like shit the minute they get stuck. They feel like they just don't have what it takes to be a developer, and it is a shame because many of them would love programming if they didn't slam into this brick wall.
And that brings me to my real point - most of us learn better if we focus on learning a few things at a time. We want to be challenged, to try new things, but we don't want to be so overwhelmed that we are paralyzed. Trying to learn testing plus everything else - like how to build a web app, how http works, how cookies work, etc - is an easy way to get overwhelmed. As a result, I usually recommend learning other things first, then coming back and learning testing later. You can always revisit your old projects and see how you would redesign it to apply what you are learning about testing, but that is only possible if you don't get overwhelmed, get frustrated, and eventually quit.
But what if I want to learn testing?! (and the million other "what ifs")
Cool, go for it! You are more than welcome to learn testing first, and then learn about web dev or any other topic. I'm sure some people have done this, and you might enjoy it. When I say testing isn't for beginners, I'm not saying it is an awful topic to learn. What I'm saying is that trying to learn testing plus everything else is a mistake.
Most people want to learn how to build web apps or something visual first, but that doesn't mean you have to start there. You can probably learn testing first. Some of it might not make quite as much sense without first experiencing the pains, but by all means don't let me stop you from learning what you want to learn.
This also doesn't mean you can't learn while pair programming or anything like that. When in environments with a mentor you can often learn a lot despite being overwhelmed because you have someone there to guide you through it all. When you get lost you aren't just stuck, and you don't feel like a failure. Someone is around to tell you, "You are doing great, this is just a ton to take in. Try X and Y instead next time!" In short, getting overwhelmed, then stuck, and finally quitting isn't as much of a concern in these scenarios.
Pssstt...
Interested in learning or practicing Go? Check out my FREE course - Gophercises - Programming Exercises for Budding Gophers.
I also have some premium courses that cover Web Dev with Go and Testing with Go that you can check out as well.
Top comments (6)
This is a really good point, and isn't something I considered when building my first "real life" application at work. I was kicking myself through the whole process for having done no TDD, but I never thought about whether I could actually formulate test cases for what I was needing to do (probably not, since I was using data from a database, our ERP and Salesforce).
Thanks for sharing Jon. I like to push myself out of my comfort zone and to try and understand topics I don't initially agree with!
You make some good points, and... I am going to force myself to stop there, bite my lip and try and learn. :)
Part of this is probably personal experience. There are likely a few people who somehow manage to learn it all and do well, or maybe they just happened to learn things in the perfect order, but after seeing many people fail because they tackled far too much at once this is where I settled.
I suspect my own personal experience of not touching tests for the first few years also played a factor. I was really young (like 10-12yrs old) and didn't even know how to setup a LAMP server so I had to rely on free PHP hosts. If I had tried to dive into anything like testing I fear it would have scared me off or frustrated me because I couldn't get anything working.
I am saying all of this basically just to say - I think it's okay to disagree with the article. Your personal experiences might have given you a perspective that I can't truly appreciate the way you do. But I do appreciate you reading and trying to understand my perspective as well :)
My personal experience is a bit biased - because I'm a Tester in my day job, and not a "Developer".
I have however been learning about coding and programming for many many years (from when I was also about 10-12). And in fairness, I am still inexperienced at "Unit testing".
However from my experience as a Test Analyst/Test Engineer of some years, I would argue there is a vast world of "Testing" beyond unit and automated testing.
And I genuinely think some of the lessons from being a test analyst would hugely benefit new Developers.
So while the headline is "don't make new devs do testing" - and that I disagree with - I can 100% sympathise with "Don't make new Dev's learn how to implement assertions before they have even learned fundamental concepts".
👍
The book Peak: Secrets from the New Science of Expertise taught me a lot about learning one specific thing at a time.
I deal with this problem in my job teaching at a boot camp. People ask, "do you teach <x>?", and I respond, "about 3 months later than you would like." It is easy to overlook all the small steps on the way to teaching a topic and incorporating it into existing competencies.
Perfect Jon. As a newbie myself, I have intuitively avoided the temptation of trying to learn testing. I can see that I need to grow more with language fundamentals and general programming concepts. For example, my goal is web-apps, so I would like to reach beyond the beginner-level and be able to competently build web-apps before testing. Here are just a few things that beginners to web-dev are presented with and it gets overwhelming...
There are the basics -> HTML, CSS, JS, Backend
Then there's more (and this is NOT including any frameworks)...
So, I'll get to testing when I get there 😂