I'm at a FANG with some of the smartest people I have ever encountered in my life, yet no one seems to agree with me that devs should not write their own tests.
There is an unwavering belief that knowing the corner cases and weak points of your own code makes you somehow better at writing the tests. We also seem to be obsessed with testing that is half-way between unit level testing and system level testing. We test APIs and features more or less in isolation.
Tests should be written by antagonistic developers who are not at all familiar with the code. They should stress the capabilities promised in the interface documentation. Hiring more people who are dedicated to testing costs a lot of money though. I don't see things changing anytime soon.
> I'm at a FANG with some of the smartest people I have ever encountered in my life, yet no one seems to agree with me that devs should not write their own tests.
> There is an unwavering belief that knowing the corner cases and weak points of your own code makes you somehow better at writing the tests. We also seem to be obsessed with testing that is half-way between unit level testing and system level testing. We test APIs and features more or less in isolation.
You're both right. Devs should write tests for their own code, but they shouldn't be the only ones writing them.
One of the problems (at least at my employer) is QA is considered a place for second-rate developers. Some of them are so bad that they rely on the devs to basically write their tests for them, by requiring extremely detailed and specific acceptance criteria. Only once have I worked with a tester that was engaged enough to really understand the requirements on their own and call out weird behavior or corner cases that weren't spelled out in advance. It was great.
> Obviously, if you look for second-rate developers to be your testers, you will end up with second-rate testers or worse!
Yeah, and to make my thoughts a little clearer: if your organization does that, it's no wonder some people come to the (wrong) conclusion that only devs should test their own code. To come to the right conclusion in such an org, you either need an outlier experience (e.g. a talented tester who chose the role against organizational incentives) or the ability to see past your own direct experiences (which is really hard).
> yet no one seems to agree with me that devs should not write their own tests.
I'll die on this hill. The developer that wrote the code by definition cannot write an appropriate test suite for it. It is entirely possible/probable that details missed in implementation will be missed entirely in test, as the developer missed them.
< controversial take> Manual QA promotes bad habits and is not a great thing to introduce to an org. SDETs/QA Engineers/Developers whose role is explicitly to create tests for an org are worth their salary 10x. </ controversial take >
Unit tests written by devs are not testing that the system does what it is supposed to do. They're testing that the code does what the programmer intended it to do. They have to be written by the programmer because they're coupled with the code.
There's a separate testing process needed (as you say) that tests if the system does the thing it's supposed to do. The programmer cannot do this, precisely because it's basically testing their understanding of the requirements.
I have my co-founders Q&A everything before rolling out to production. It's a pain, but it's saved us a few headaches where I was just following the golden path and missed some obvious problems.
Depends. If the 'unit' is big enough to have an interface spec then a different dev should write the test. If you're doing function level unit testing, a dev should write it. There's a grey area between those two extremes.
My original post was intended to focus on system and api level testing but I wasn't clear on that.
Reminds me of a NASA failure report where they determined the reason the satellite failed immediately after launch was because they built their own circuit-test device to match their assumptions rather than reality. But it passed their test. Now it is spinning uncontrollably above us.
Developers also risk the "I thought of that already so I don't need to test it thoroughly" pitfall, eventually leading to the usual "we didn't think it was possible fail like that"
I'm with you on that hill. Good QA have a vastly different mindset to devs - and they're not prone to the unconscious tunnel vision you develop when writing code that assumes a particular approach.
However, I have to say, depending on your product, some of the best damn QA I've worked with aren't writing integration tests, at most they're using SQL to get the DB into an appropriate state, and then they're doing the rest manually, but it's really about their mindset, manual is just the easiest approach for them. Manual encompassing "click on the thing" as well as "hit the endpoint with Postman".
It's their mindset I value most. And some of the best pairing I've ever done is with a QA to write integration tests.
You can't finish a project without developers and you can finish it without testers.
I've seen a tester changing requirements on the go, delaying features for things that aren't even the case. Those change requests then cause bugs, because... Dev.
The most important thing for a dev is domain knowledge and letting them care about the product.
Usually, when the original Dev leaves ( monolith), it's enough to call the project abandoned, but maintained. Leaving the devs wanting to spend a minimal amount of work with it.
> You can't finish a project without developers and you can finish it without testers.
...for a given value of finished. My value of finished involves "no significant bugs that cost thousands of dollars of revenue per day". And in the past, QA has repeatedly caught such bugs, despite ample testing by the devs.
It really comes down to the mindset, and the approach - a QA approaches testing code differently to a dev who wrote the code.
> I've seen a tester changing requirements on the go, delaying features for things that aren't even the case.
In a well-functioning team, requirements should be explicit, understandable, achievable, realistic, and _agreed upon_ from the get-go. Once agreed, devs and testers work to those requirements. If, during the development cycle, it's realised that a requirement is lacking, or indeed, entirely absent, then it should definitely be discussed between devs and QA, at the very least, and _agreed upon_ - noting that sometimes, it might be a reasonably significant change in requirements that the business needs to be involved also in reaching that agreement. It may change delivery time, or delivered capacity etc.
The ideal, from my POV, is having testers fully involved in the planning discussion / backlog grooming whatever you call it, where your team ensures that the requirements from business are specific, realistic, achievable, and useful. And then, hopefully, given the entire team's domain knowledge, that is, domain knowledge from developers AND QA, because they will have a metric shit ton also, and I find it curious you only ascribed that to devs... ... then, hopefully you can determine which requirements are missing, get the business to agree, and then make those part of the agreed upon work also.
You'll note that I'm not speaking on dev vs. QA, rather on process and team structure. The issues you faced are not issues inherent to QA. The issues you faced are due to process and team structure.
They are worth more in the same sense a salesman is worth more than the dev. Without the dev neither have anything to do, yet they all provide equally valuable work. Perhaps it's not a matter of value, but supply and demand.
I could understand Manual QA does not scale, but why bad habits? What if the person doing Manual QA of an application also then writes tests afterwards based on what they have determined are the likely problems in the application - which is what I would do if I was going to write (ui) tests, test it by hand first.
> What if the person doing Manual QA of an application also then writes tests afterwards based on what they have determined are the likely problems in the application
I wouldn't really call this manual QA then. I'm describing the thousands of orgs whose QA processes are limited to "These people will run these five thousand test cases by hand for every release", and/or "These people will be handed a ticket and manually click all the buttons before marking it done"
>The developer that wrote the code by definition cannot write an appropriate test suite for it. It is entirely possible/probable that details missed in implementation will be missed entirely in test, as the developer missed them.
The same is true of pretty much everybody - PMs and QA included. Everybody misses details and edge cases.
It's better to write the test suite in a readable form and get everyone to take a look at it.
Unit tests are almost entirely unsuitable for this purpose most of the time.
> The same is true of pretty much everybody - PMs and QA included. Everybody misses details and edge cases.
No, the same isn't true of everybody. They would all have to miss the exact same details and edge cases, was the point. It's the same reason that you have sensor redundancy, you don't have the same sensor measure twice and trust it.
They argued that separate people should look at a problem so as not to make the same mistake twice:
> The developer that wrote the code by definition cannot write an appropriate test suite for it
You said that issue could be applicable to everyone:
> The same is true of pretty much everybody - PMs and QA included. Everybody misses details and edge cases.
I pointed out that the issue can't be true of everybody, since everyone other than the original developer would generally avoid it. You then said I repeated what you said. Which is it?
I'd argue that while they can't "do" their own testing, developers should be writing Unit tests that prevent their code from being broken in future. They should also be writing tests that exercise their code so they find corner cases that were not obvious when coding.
The problem is it's difficult to define what that is (and particularly to teach a junior Dev what to do).
> There is an unwavering belief that knowing the corner cases and weak points of your own code makes you somehow better at writing the tests.
This is a very common -- but inevitable -- misunderstanding.
The real reason the same person should write tests and code is if you find a person who is competent enough in both technical domain and problem domain to write the tests -- you definitely want that person to write the code as well.
See how it's not "developers should write tests"? It's "domain experts should write the tests... and domain experts should write the implementation."
Black box test - Testing a unit without any information about its internals. You provide inputs, you record outputs, and you have a spec.
By definition, the author of a unit cannot write a black box test for it. Any test they write is going to be a white box (clear box?) test, because they know how the unit works.
If you interpreted the spec incorrectly when writing the unit, you're going to interpret it incorrectly in exactly the same way when writing the test. White box testing has its place, but you need a second person if you want to do black box testing.
Writing down your program's test cases should not add much time (assuming you have test infrastructure setup like you should), since you are already having to consider these things to simply figure out what the right logic is. With a little practice, you find a good rhythm for how far to take it for yourself. In my experience, I find this actually leads to faster and more correct solutions.
2. Collect tests while in review to cover the requirements
Once you've written it though, it's always important to try and get others to look over your code and try and find flaws. Ideally, they can even write tests for you to add to the feature. This is just a standard part of any good peer review.
3. REGRESSION TEST
Finally, though I'm not sure it matters very much who writes it, regression tests are something I never see stressed enough. I feel like if you are serious about testing, every bug should be required to add at least one test to the suite before it can be closed.
That sounds like an incredibly slow feedback cycle. How would that work? Write some code, check it in, wait for someone else to write tests... and come back in hours/days/weeks to fix any issues?
Getting constantly dragged back to fix last week's bugs sounds like a chapter from Dante's Inferno. I'd rather discover them while the code is fresh in my mind.
I've seen both types of org layouts where I've worked (we moved from one to the other).
Initially separate QA teams that would write tests, a subset of which might do manual testing in the UI.
The feedback loop for this was brutal as you suggest and caused a lot of problems, with delayed breaks that become hard to fix and debug. It's also hard for QA to often know what the code is doing or interact closely with the dev teams. You can try to get them to be as close as possible, but it doesn't work super well.
Now devs are responsible for writing tests and teams think about potential failures when designing things/discussing the plan with their team. They were supposed to consider these things before too, but the incentives weren't aligned - now they are. We have infrastructure teams to make automated testing as easy as possible and spin up a test environment where you can see your change, etc.
I think this model is better, testing well is hard and reasoning about failures and how things can go wrong is an important skill to develop. Offloading this to a different team feels like a variant of the dev that 'just writes features' and doesn't consider actual deployment.
This is often made doubly worse by companies that have QA teams often treating them as second class citizens both in status and in pay. I think it's better to have it be part of the job of the person writing the feature also write the tests, it doesn't help that writing tests is something few people know how to do coming out of school.
In the past, I had pseudo-pair programmed in order to test. We'd agree on the external-facing API and pair-program a slow in-memory implementation. Once that was completed, we would split off and one of us would write test cases against the API (fixing up the in-memory implementation as needed) while the other would work on a proper database-backed implementation.
I haven't done this in probably 7 years, though. Mostly because I haven't cultivated this kind of working relationship with my coworkers.
I'm taking about API and system level tests. Unit tests vary in scope between 'test a function' and 'test a unit interface'. Former should be done by the dev during development. Latter should be done by someone else. It's a grey area between those extremes.
I'm coming from a systems programming and embedded background so I have no idea if a web dev or someone else should follow my advice, but I suspect so.
I suspect you think the developer writes the code and then the QA engineer writes tests for that code. That's the wrong way round. The tests are written first, and they all fail, then the dev has to write code to make them pass. By definition it's literally impossible to write untestable code that way because then the tests won't pass.
It's the principle of TDD but separated in to different roles. It works well and produces good results but you need exceptionally good planning upfront to actually do it.
That surely implies a specification which, in my experience, is a rare thing in these Agile days.
> the QA engineer
In the last 10 years of contract and perm jobs, only once have the QA people actually written tests (and that was largely translation of an existing manual suite to a node-based automatic runner.) It's pretty much always been "these are the things the devs/product manager/pm wants to test for these changes, please test those and approve".
Usually it's done as a collaboration between the systems architect and the QA team. The process is essentially "design the system architecture -> document the APIs -> write the tests -> implement the code -> QA". It takes a level of rigour and planning that most teams don't want to do, and it relegates developers to a pretty minor role in the whole development process. They end up just filling in the blank bits in someone else's design. Most changes in team structure over the past couple of decades have been about developers taking on more of the responsibilities rather than less.
It's actually one of the aspects of TDD that makes it so robust. If you properly design your code and really think about its APIs you get a better app at the end. It does take longer to get something a user can see though, but often the process gets to a finished iteration of an app quicker because there's fewer cycles of debugging and fixing needed.
> The process is essentially "design the system architecture -> document the APIs -> write the tests -> implement the code -> QA". It takes a level of rigour and planning that most teams don't want to do
That's a very charitable way to say it, on my case I would call this kind of process very convoluted and similar to early 2000s style development. I obviously would not want to work in such a bureaucratic environment where every small tech decision has to go through multiple boards.
I obviously would not want to work in such a bureaucratic environment where every small tech decision has to go through multiple boards.
Everyone who works on the app is making those decisions no matter what you do. The difference is that in the "old style" the decisions were made before the code is written, and in the agile "new style" the decisions are made after the code is written. Often that's fine, because developers are generally good at their work and they make decent decisions, but sometimes they get it wrong and that's when code design issues arise. It's also what leads to automated tests failing to test for a lot of cases that a good QA engineer would have written tests for. Those things have an impact on the user.
A huge amount of the code in apps we use every day was never designed. No one thought it through. No one considered the edge cases. Features are thrown together in a week and 'sort of' work. Every time you see a shitty broken website, or a bug in production, or some crappy slow thing that should be fast the reason behind the problem is that the developers who made it didn't take the time (or even have the time in really bad companies) to think about what they were building. A lot of developers like that working environment because they can hack on things and move on to the next challenge quickly. That's fun. I argue it's also bad for users, and I care more about users than I care about developers (and I say that as a developer whose been making web stuff for almost 25 years.)
I'm not arguing that we go back to Prince2 and waterfall. There's a limit to my tolerance of bureaucracy too. I'm saying that things have gone a bit too far the other way, and many developers need to spend more time planning what code is written before leaping in and coding up the first solution they think will pass the acceptance criteria someone from product wrote.
> I'm not arguing that we go back to Prince2 and waterfall.
Earlier you proposed: "design the system architecture -> document the APIs -> write the tests -> implement the code -> QA". This is precisely waterfall. Detaching the term from the emotions and bad PR, there are decades of real experience of people who did that and discussed their results.
The bureaucracy is not the cause. I argue the causality is: the "design first" assumption -> the "throw it over the fence" practice -> everyone blames everyone -> Prince2 comes to the rescue.
> I say that as a developer whose been making web stuff for almost 25 years.
> I'm saying that things have gone a bit too far the other way, and many developers need to spend more time planning...
I'm not sure I fully agree, unless we want to define waterfall as "anything where a bit of time is spent up-front to decide how a part of the system should work" :)
For me, waterfall is where every single aspect of the project is pre-defined, and cannot be changed during development without serious pain and lots of awful bureaucracy
But in the above workflow, there isn't anything stopping us from making a loop for example on a sprint by sprint basis, and using feedback from both the tests and changing requirements to improve the design, update the APIs, change the tests, etc.
I suppose we could argue that this is "mini-waterfall" but it works in my experience :)
> I would call this kind of process very convoluted and similar to early 2000s style development
The 2000s style you are referring to was centered around "features" or "business cases". One unit of work = one feature. The bureaucracy is orthogonal.
Modern "agile" style is centered around "sprints". One unit of work = one sprint duration.
The bureaucracy inevitably involves synchronization points and enforces more or less linear process, which usually implies longer "real world" feedback loops. Lack of bureaucracy allows for concurrency and possibly shortens the feedback loop, which may be nice at first, but then you slowly informally incorporate the bureaucracy back - code owners, design sessions, etc..
The bureaucratic process is not inherently bad, the agile process is not inherently good. In some cases quick turnaround of basic features is more profitable, in other cases correctness may be most important. I can agree that quick feedback is more fun to work in, but it is not necessarily the best way.
So how do you test the design? I ask this sincerely. To me it seems that it's rare to know in correct detail what the design is supposed to do in advance, but also that even if you do, it often has oversights that aren't spotted until you've built them.
You still work in sprints and deliver features to the user regularly, and iterate to the right solution. I'm not suggesting you design all the code in the entire app and write all the necessary tests for every feature at the beginning; you still only design the bits that are needed right now. The development process just has a lot more upfront thought time, more upfront test writing time, and less coding time because if your code passes the tests you know it's correct (based on the assumptions about what 'correct' is right now.) There's always going to be a requirement to go back and improve things, pay down technical debt, fix design issues, etc no matter what your development approach is.
> yet no one seems to agree with me that devs should not write their own tests.
Change Request (or whatever you call it in your flavor of agile) is the source informal description of behavior, while Specification, Code and Tests are three distinct formal descriptions of the same. If any of those three are written down by the same person, assumptions and thinking errors translate to the other largely defeating the very purpose of writing down another formal description in the first place.
Unit tests became mainstream with proliferation of weak-dynamic languages (JS, Python) and concepts like TDD largely became mainstream due to lack of formal interface specification capabilities in the languages themselves. Stricter languages (Java, C++) cover huge portions of the testing in the type system. Tests written by the developer are okay if they are used as a substitute for a formal type system. However, tests intended to catch logic errors will contain the very same logic errors found in the code and such tests will only give you false confidence.
It does not mean that tests must be written by a dedicated QA, but rather that tests should be written by a different person for them to serve the purpose they are intended to serve.
Count me in as one of those who disagree with you.
I 100% side with the grandparent comment. When you've worked with a great QA, it's night and day vs a dev writing their own tests, but a dev not writing its own tests is a nightmare.
Ideally there's a place for both and they work very closely with one another to make the software stable at all levels. It's arguable the SRE is the new QA engineer.
I'll give an example for why the original author of the code should write the test. Say you write a sort and for performance reasons you use a different algorithm beyond collection size 100. This is prone to bugs around collection size 100. Your test needs to shed light on this dark corner. A QA generalist can't know that. They write some generic test cases. Size 0, 1 and 2 since they are inherently dark corners. Then some medium size and some large collections. They'll likely miss the 100. And the bug that's there for size 99.
You need both and ideally the original author writes the test and somebody else reviews the test thoroughly. That reviewer should have an intimate understanding of the spec you are implementing.
The more formal that spec, the less need for that external reviewer since the less ambiguity there is leaving room for missunderstanding. In a perfect world, the spec is completely formalized and instead of a test that shoots in the dark, you'd write a formal machine-verified correctness proof, automatically covering all cases. Then you would not need that external reviewer and could just have the programmer do it by themselves.
> We also seem to be obsessed with testing that is half-way between unit level testing and system level testing
I think that's where most testing should live. Testing single modules means you don't test how they plug together and makes it hard to refactor responsibilities between modules, such that it often doesn't happen. Full system level testing is painful to write as you often have to mock out the world, and painful to run as it it usually slow.
The middle ground where you test a block of modules together through the top interface is a great middle ground. It does not replace the others- you need some full system level testing to check that your system integrates properly, and most modules will need some unit testing (and some will need a lot), but it's the best "bang for your buck" in terms of invested effort.
QA teams and devs write totally different tests. Devs go about it to help future refactoring, e.g. codify what the feature is supposed to do, so that if we change it in the future, we will not inadvertently break something. QAs write tests that look from the point of the user.
QA tests are arguably more valuable, but writing testable software itself can only be done if the devs too are invested in the task.
Maybe we can form DevQA teams? the way we did for DevOps and DevSecOps?
But alas, I still think having everyone though out the whole stack invested in writing tests makes the the final product better.
You're getting heavily downvoted and I'd love to know why. I've seen similar attitudes toward testing among the groups I've worked with, nobody really wants to do it.
Are folks downvoting this because they don't like testing? Is this idea that prevalent?
I think it's more appropriate to say, the quality of (enterprise?) software should not rely SOLELY on tests written by a software developer.
Is it not common knowledge already that code review is the single most valuable tool in getting rid of bugs? I remember reading it on Code Complete, maybe The Pragmatic Programmer. Can't remember.
I think there's still value in writing your own tests, at least with regard to refactoring (and sleeping better at night after deploying to production).
> Is it not common knowledge already that code review is the single most valuable tool in getting rid of bugs?
No, it isn't. Because there isn't that much evidence it is. It is a good tool, but "most valuable tool"? That's a very bold claim. I would still place code analyzing tools, linters and fast feedback cycles (= fast compilation and ability to check changes) over code reviews, if only for the fact many code reviewers tend to divert into "I like this way better" arguments.
Yeah definitely poor choice of words there. I misremembered the book. Anyway here's a cherry picked excerpt from Code Complete, 2nd edition:
> Glenford Myers points out that human processes (inspections and walk-throughs, for instance) tend to be better than computer-based testing at finding certain kinds of errors and that the opposite is true for other kinds of errors (1979).
> This result was confirmed in a later study, which found that code reading detected more interface defects and functional testing detected more control defects (Basili, Selby, and Hutchens 1986). Test guru Boris Beizer reports that informal test approaches typically achieve only 50–60 percent test coverage unless you're using a coverage analyzer (Johnson 1994).
So I would conclude that the best approach is to use both code reviews/inspections and automated tests/linters/analyzers.
I'm not debating automatic vs human approaches as much as how code reviews fit and why blind focus on them misses the forest for the trees in regards to other human approaches. When it takes 20 minutes from starting compilation to getting to the point of change, the Dev/QA/Review trifecta looks a lot different than when this takes 3 minutes. (Ideally,) developers are a lot less likely to make errors out of fatigue. They are more likely to pay attention to detail (when it takes 20 minutes, it's easy to go "whatever QA/reviewer will verify"). Reviewers start checking out the code and testing the change manually, rather than just looking at the code and pawning it off to QA. QA gets more time on their hands to proactively eliminate issues by being part of the design, instead of being the guys pointing out mistakes after the fact. Having shorter compilation cycles paves the way to increase the quality of all three segments of this cycle, yet it is often overlooked the most despite seeming so obvious.
The part about QA is perhaps the most infuriating. Most business logic is so simple it can be presented as test/result matrices, which generally translate cleanly into requirements and automated tests, are easy to reason with, implicitly have three parties with different perspectives, and should be blind to technical details giving devs more freedom. Yet instead, this piece gets relegated to "software requirement engineers" writing walls of text, who tend to forget even the simplest cases (null, empty list/string, etc.), and any automated tests are then designed by the same developers making the implementation and only caught after the fact by manual QA a few months later.
> Hiring more people who are dedicated to testing costs a lot of money though. I don't see things changing anytime soon.
Doesnt Google have a Software Developer in Test role? I work in a bank and every project has these people - their only job is to write automated tests (usually in Python robot framework).
Yes, I was hired at Google to do dedicated testing (Test Engineer was my title). Note that at Google, many test engineers were "supposed to" build test infra, not write tests or do testing. I was brought on to test some systems that were critically important, but built by a team that focused more on operations than coding. I set up a continuous build, fixed all the broken tests, and prevented team members from checking in broken code. I don't think developers can be entirely trusted to QA their code.
There is an unwavering belief that knowing the corner cases and weak points of your own code makes you somehow better at writing the tests. We also seem to be obsessed with testing that is half-way between unit level testing and system level testing. We test APIs and features more or less in isolation.
Tests should be written by antagonistic developers who are not at all familiar with the code. They should stress the capabilities promised in the interface documentation. Hiring more people who are dedicated to testing costs a lot of money though. I don't see things changing anytime soon.