Test-driven development: A great idea hiding behind a terrible implementation?(itnext.io)
itnext.io
Test-driven development: A great idea hiding behind a terrible implementation?
https://itnext.io/test-driven-development-is-dumb-fight-me-a38b3033280c
175 comments
Reading this article got me thinking that the problem isn't TDD it self but the interpretation of it from a specific programmers perspective.
One other poster noted that TDD is great when you know what your inputs and outputs are, ergo a toy function/project but I disagree as a programmer you should know that for every function you are writing before you start writing the function since you need to settle on return type(it's true for loosely typed languages too) so I'd conclude that maybe the OP is misussing the TDD paradigm
Is there a way to read this without creating an account in Medium?
https://outline.com/2cNZTz
Alternatively incognito or no js should do the job also.
Alternatively incognito or no js should do the job also.
Not much to add except that when j tried TDD, I had to have this mentality of typing out code as fast as I could, going back to the test, fixing stuff, back to code, learn the mistakes, etc.
While my dev approach is more about think, think, think harder, code, compiler barely complains, fix small issues, write test, done.
TDD felt very uncomfortable because the thinking part didn't seem to be emphasized much. It's like keep going, you iterate again real soon in this code, now again, and again.
Maybe I got it wrong, I don't know. But I share the author's frustration.
While my dev approach is more about think, think, think harder, code, compiler barely complains, fix small issues, write test, done.
TDD felt very uncomfortable because the thinking part didn't seem to be emphasized much. It's like keep going, you iterate again real soon in this code, now again, and again.
Maybe I got it wrong, I don't know. But I share the author's frustration.
I'm with you and the author on this.
First thing: they do not define which kind of TDD they are talking about. Second thing: without really good test coverage any kind of larger refactoring is gambling with reliability and will bite you at some point.
What kind of TDDs are out there?
Don't seem fair to call out author on not writing tests because they never said that.
Don't seem fair to call out author on not writing tests because they never said that.
Right, I write tests for existing functionality. And I decide what test to write after I write code. In the spirit of this article, I would assert that a simple two line integration test could cover a large portion of code depending on how many parts it requires to work together correctly.
https://github.com/testdouble/contributing-tests/wiki/Test-D...
This wiki has great content about the different types of TDD. Reading it helped me get useful insights about my approach and my gripes with TDD. In particular it's interesting how different approaches to testing influence heavily the design of your code.
This wiki has great content about the different types of TDD. Reading it helped me get useful insights about my approach and my gripes with TDD. In particular it's interesting how different approaches to testing influence heavily the design of your code.
London school, Chicago school, outside in, inside out. Sociable unit tests, solitary unit tests, state verification, behaviour verification and so on
There are so many attributes.
There are so many attributes.
> What kind of TDDs are out there?
I have never actually seen somebody writing all of the tests before implementing the code even if they claimed doing TDD. Parts of tests maybe but I think that things rarely go the way the definition is spelled out.
> Don't seem fair to call out author on not writing tests because they never said that.
Fair point. I have written my comment halfway into the article, the author makes a point about tests at the end.
I have never actually seen somebody writing all of the tests before implementing the code even if they claimed doing TDD. Parts of tests maybe but I think that things rarely go the way the definition is spelled out.
> Don't seem fair to call out author on not writing tests because they never said that.
Fair point. I have written my comment halfway into the article, the author makes a point about tests at the end.
> I have never actually seen somebody writing all of the tests before implementing the code even if they claimed doing TDD.
I had an architect who did exactly this. It was awesome, one could just look at his code and see where it would fail because it didn't occur to him to either test for that case or actually think what the code does. His only explanation would be "but it passes the tests". Later he was made into CTO.
In a way, not testing for edge cases that are found during development is quite similar to commenting on article one hasn't fully read.
I had an architect who did exactly this. It was awesome, one could just look at his code and see where it would fail because it didn't occur to him to either test for that case or actually think what the code does. His only explanation would be "but it passes the tests". Later he was made into CTO.
In a way, not testing for edge cases that are found during development is quite similar to commenting on article one hasn't fully read.
I think the driven part is bad. Using tests are fine, it should just not drive your development efforts.
Sometimes you do have to make your code more "testable" on purpose though. But yeah, writing the tests first doesn't always work. YMMV.
True. I just run into these situation too much because I functional style code where there is very little internal state and try to use pure functions as much as possible. This narrows down the code that has to be written on a more testable way.
In college we were always taught to do TDD on large projects, and everybody I know does TDD(at least here in France). I can even think of working on a project that's not TDD. You need to look up Agile, Clean code and Xtreme Programming ;-)
This comment in the original article is really to the point:
I think one of the biggest values of TDD is it teaches developers how to write unit testable code, which, if you are new to unit testing, can be quite hard to get your head around.
As for its usefulness in ‘real-life’, I’m going to answer with a solid ‘it depends’.
Anyone who dismisses it is missing out on some potential big advantages, anyone who is a 100% TDD zealot is probably either wasting time or lacks extensive real world experiance.
I think one of the biggest values of TDD is it teaches developers how to write unit testable code, which, if you are new to unit testing, can be quite hard to get your head around.
As for its usefulness in ‘real-life’, I’m going to answer with a solid ‘it depends’.
Anyone who dismisses it is missing out on some potential big advantages, anyone who is a 100% TDD zealot is probably either wasting time or lacks extensive real world experiance.
I somewhat dislike the TDD cargo-cult myself; but this is such a shallow opinion piece, how is it on top of HN?
25 minutes, 16 points - all that it takes?
25 minutes, 16 points - all that it takes?
HN loves shallow opinion pieces, especially when they're contrarian. They give us a chance to wade into the comments and demonstrate how smart we are, either by agreeing or disagreeing!
Great to see the author tackle such a broad topic after 3 months of bootcamp and 1? year of professional development.
Regurgitating others' opinions and making multiple unfounded assertive statements is key to demonstrating he has already mastered the software domain.
Regurgitating others' opinions and making multiple unfounded assertive statements is key to demonstrating he has already mastered the software domain.
I don't think that's a fair assessment.
He talked to a bunch of experienced devs and summarised their opinions. And then he shared his own opinion on the matter.
Nothing wrong with that.
He talked to a bunch of experienced devs and summarised their opinions. And then he shared his own opinion on the matter.
Nothing wrong with that.
Nothing wrong, but also nothing worth discussing. It doesn’t qualify as a good research or an opinion of a subject matter expert - just few banalities in a popular genre of provokative tech blog post.
Care to attack the arguments next?
He didn't publish fact. He published opinion.
The context of that opinion is highly relevant and not qualified in the article or a bio.
His insta page listed in the bio however gives an insight into his experience.
So yes, I feel perfectly content to raise his lack of experience.
I'm fed up of noise posing as insight.
The context of that opinion is highly relevant and not qualified in the article or a bio.
His insta page listed in the bio however gives an insight into his experience.
So yes, I feel perfectly content to raise his lack of experience.
I'm fed up of noise posing as insight.
[deleted]
Its always like this. Last month the article was about how OOP was useless and a waste of billions of dollars, yet the author had like 2 years of experience as a Php developer (in 2019?). It didn't stop 2 of my sub par coworkers from sharing the article and acting like the author had any creds or experience at all to be saying such things. Generally I never read blog posts from no name people claiming industry standards should be destroyed. Its just a pointless exercise.
The experiences of beginners are as valid as anybody else's.
It creates an unfriendly culture if people are told they can't talk about their frustrations and challenges without having x years of experience first.
It creates an unfriendly culture if people are told they can't talk about their frustrations and challenges without having x years of experience first.
>The experiences of beginners are as valid as anybody else's.
In certain situations they may be even more valid. But when it comes to software processes you really need to have lived and breathed them in order to mount a credible argument.
>It creates an unfriendly culture if people are told they can't talk about their frustrations and challenges without having x years of experience first.
Nobody is denying this person the right to talk about their frustrations.
In certain situations they may be even more valid. But when it comes to software processes you really need to have lived and breathed them in order to mount a credible argument.
>It creates an unfriendly culture if people are told they can't talk about their frustrations and challenges without having x years of experience first.
Nobody is denying this person the right to talk about their frustrations.
>Nobody is denying this person the right to talk about their frustrations.
bjornsing's comment is implicitly highly critical of them doing so.
bjornsing's comment is implicitly highly critical of them doing so.
The headline title is beyond a "frustration", it reads like a universal assertion.
Something like "I dont like TDD" or "I struggle with TDD; here are my thoughts" would at least ground us in our expectations.
Something like "I dont like TDD" or "I struggle with TDD; here are my thoughts" would at least ground us in our expectations.
The experience of a beginner with a certain tool is quite important. E.g, if Linux is not user friendly to newbies something could be done about that.
But some tools require expertise and a beginner might not get the entire picture yet. E.g, if someone with 1 year of physics experience claims Quantum Mechanics to be dumb, is that a valid opinion?
But some tools require expertise and a beginner might not get the entire picture yet. E.g, if someone with 1 year of physics experience claims Quantum Mechanics to be dumb, is that a valid opinion?
This isn't some conceptually difficult thing like quantum mechanics, it's something designed to make software easier to build.
If it doesn't in fact do that for this person it's totally valid to mention that.
If it doesn't in fact do that for this person it's totally valid to mention that.
It's valid to have an opinion on something, another thing is having a well-founded opinion. I love vim and my opinion is that it's better than Emacs.
But I used VIM for a decade and Emacs for 6 months.
Is anyone going to take my opinion on Emacs seriously, knowing that these tools take time to master?
But I used VIM for a decade and Emacs for 6 months.
Is anyone going to take my opinion on Emacs seriously, knowing that these tools take time to master?
> Is anyone going to take my opinion on Emacs seriously, knowing that these tools take time to master?
Maybe not, but you're welcome to publish an essay on what you think.
Maybe not, but you're welcome to publish an essay on what you think.
True, and everyone is welcome to voice their opinion. I'd encourage that, but it still doesn't make it 'valid' for a larger audience. :)
I think the idea is to avoid calling something "dumb" when you have not enough understanding and experience in it to pass such arrogant judgement.
>experiences of beginners are as valid
What does this even mean? Their experiences are valid?
What does this even mean? Their experiences are valid?
I find it amusing to read posts like the authors. I bet he also does not even use Agile Methodology lol ;-)
He's right, but also wrong. It really depends on what you are developing.
TDD is awesome when fixing bugs (as opposed to writing features), when writing straight up business logic (especially when there are a lot of edge cases) and when you know exactly how something is going to work.
It's really bad when doing anything that requires exploration and research (which is the example in the article).
TDD is awesome when fixing bugs (as opposed to writing features), when writing straight up business logic (especially when there are a lot of edge cases) and when you know exactly how something is going to work.
It's really bad when doing anything that requires exploration and research (which is the example in the article).
I work for a Danish municipality and we buy quite a lot of development from various software houses. Being the public sector we track and benchmark almost everything, and we actually have a dataset on automated testing that’s been running for two decades.
It’s hard to use the data, because we’re comparing different projects, teams and suppliers but our data shows no advantage in choosing the companies that are very test-focused.
They are often slower, more expensive but have the same amount of incident reports as the companies which tests less or doesn’t do automated test at all.
It’s hard to use the data, because we’re comparing different projects, teams and suppliers but our data shows no advantage in choosing the companies that are very test-focused.
They are often slower, more expensive but have the same amount of incident reports as the companies which tests less or doesn’t do automated test at all.
Interesting. My intuitions (as a developer of 25 years experience) are that testing can be a big tax on development velocity; perhaps 60% of time is spent on writing tests, especially in a more complicated code base where the choice is between tests with lots of mocks (=> brittle against code change), or tests with lots of data setup (=> brittle against schema change), where the tests are more verbose than the code under test.
I also think testing compensates for communication inefficiencies when developing with a larger team with developers with less tenure and experience. I'm not sure this tax is avoidable as you try and scale up organizationally.
Code architecture also has a significant effect on the cost of writing tests, and TDD was originally propounded as a way to ensure that code is testable, but with object-orientation it tends instead to lead towards dependency injection and pluggable interfaces purely for testing rather than reconfiguration, and you end up with overly abstract software.
More functional code, and architecture which increasingly represents control flow as data flow, is a better direction to aim in, IMO. That argues towards streaming and messaging techniques more than interfaces and APIs.
TDD is great for fixing bugs, less great for software design. I think the key reason is that the best design is in tension; it's a solution being applied to several problems, and triangulating that point starting from a single problem is both (a) further away from the solution, and (b) unlikely to be close to the final design unless you were really lucking in choosing the test problem.
I also think testing compensates for communication inefficiencies when developing with a larger team with developers with less tenure and experience. I'm not sure this tax is avoidable as you try and scale up organizationally.
Code architecture also has a significant effect on the cost of writing tests, and TDD was originally propounded as a way to ensure that code is testable, but with object-orientation it tends instead to lead towards dependency injection and pluggable interfaces purely for testing rather than reconfiguration, and you end up with overly abstract software.
More functional code, and architecture which increasingly represents control flow as data flow, is a better direction to aim in, IMO. That argues towards streaming and messaging techniques more than interfaces and APIs.
TDD is great for fixing bugs, less great for software design. I think the key reason is that the best design is in tension; it's a solution being applied to several problems, and triangulating that point starting from a single problem is both (a) further away from the solution, and (b) unlikely to be close to the final design unless you were really lucking in choosing the test problem.
Agreed and learned a few things. I think you should blog more :]
One question: are they somehow more efficient in answering to an incident report?
My conjecture: I am not so surprised at these having the same % of failures - after all the TDD will not magically lead everyone to think of all the possible ramifications; you write tests for the case that you can "imagine" just like a non-TDD developer will implement logic to cover cases they can "imagine". But on the other hand, if after fixing the bug you need to prove that you haven't caused some other side effect, then having a full test suite in place should be more efficient than retest everything again (or less risky than "ok, fixing module W should not impact X, Y and Z, so we test X only and ship...").
My conjecture: I am not so surprised at these having the same % of failures - after all the TDD will not magically lead everyone to think of all the possible ramifications; you write tests for the case that you can "imagine" just like a non-TDD developer will implement logic to cover cases they can "imagine". But on the other hand, if after fixing the bug you need to prove that you haven't caused some other side effect, then having a full test suite in place should be more efficient than retest everything again (or less risky than "ok, fixing module W should not impact X, Y and Z, so we test X only and ship...").
> are they somehow more efficient in answering to an incident report
No. The only thing that consistently affects speed is size of the suppliers, the bigger the slower.
No. The only thing that consistently affects speed is size of the suppliers, the bigger the slower.
Why is this downvoted, it seems like a good point.
Also @moksly's point seems at odds with an apparently highly regarded piece of software, SQLite.
Also @moksly's point seems at odds with an apparently highly regarded piece of software, SQLite.
most projects can't move as slow as sqlites development does.
A software such as sqlite is in the rare situation that stable releases are more important than anything else.
Everyone I've worked with got payed for features though, not stability
A software such as sqlite is in the rare situation that stable releases are more important than anything else.
Everyone I've worked with got payed for features though, not stability
I guess these are good points. The last line especially.
Yet it's obvious to me that correctness and stability should be features, and more fundamental than all others. It's not as if a non-extreme amounts of testing is all that expensive.
Yet it's obvious to me that correctness and stability should be features, and more fundamental than all others. It's not as if a non-extreme amounts of testing is all that expensive.
That hasn’t been my experience at all. Test-oriented firms and test-oriented projects have had far fewer incidents and the incidents they have had have been resolved much faster. The data has been so conclusive that our exexutives are mandating that we test. Maybe the difference is automation? Automating the tests is key.
This may hold some of the answer. IMO, tests are basically automated debugging, that you can run as many times as you want. To take full advantage, you should run them basically whenever you can, in the background of editing, forced to succeed upon merge, etc.
> forced to succeed upon merge, etc.
I like this approach and it was used heavily in a previous role by both the devops and development teams in a company I worked for.
However it can come with a cost if the tests are not targeted enough or there are simply too many tests to run within a reasonable period. At one stage tests were taking 20-30 minutes to run, so you could be waiting an hour or more sometimes to find out whether the change you pushed went green or red. Often this meant people pushing before their lunchbreak or at the end of the day and effectively leaving the build broken for many hours, with others unable to push unless they included a fix for someone else's breakage.
I like this approach and it was used heavily in a previous role by both the devops and development teams in a company I worked for.
However it can come with a cost if the tests are not targeted enough or there are simply too many tests to run within a reasonable period. At one stage tests were taking 20-30 minutes to run, so you could be waiting an hour or more sometimes to find out whether the change you pushed went green or red. Often this meant people pushing before their lunchbreak or at the end of the day and effectively leaving the build broken for many hours, with others unable to push unless they included a fix for someone else's breakage.
I see a lot of teams/projects where the tests take 20 to 30 minutes. Like that's the threshold where you can just barely get anything done, so things grow to that size, development velocity grinds nearly to a halt, and they stop growing. So everything you see is about that size.
Personally I need tests to run in a few seconds. I work on a large project that does it so it's definitely possible.
Personally I need tests to run in a few seconds. I work on a large project that does it so it's definitely possible.
I am lucky enough in my current role to have a lab environment that is almost 1:1 with our production environment, so we use testinfra to test all our VM's in parallel, with tests tailored for each VM to the task it performs (database, application, load balancer, DNS, LDAP, SMTP etc). We can run tests on an entire environment in under 2 minutes.
Far more holistic than the 20-30 minutes I described in that previous role, where the whole set of tests was run in a single vagrant VM, usually recycled to save time on spinning up a new VM for each run.
There's a lot of great stuff you can learn from devops, but there also seems to be a large amount of cargo culting where people have cut & pasted certain solutions from a blog or something without understanding how to adapt it to their environment and make it work properly for them.
Far more holistic than the 20-30 minutes I described in that previous role, where the whole set of tests was run in a single vagrant VM, usually recycled to save time on spinning up a new VM for each run.
There's a lot of great stuff you can learn from devops, but there also seems to be a large amount of cargo culting where people have cut & pasted certain solutions from a blog or something without understanding how to adapt it to their environment and make it work properly for them.
Can you describe your experience in more detail? How big is your data set here? What is the size of the effect you are measuring?
Your dataset is very important. Is there a place where we can publicly analyze it??
Agreed. I'm pro-TDD, but it does nobody any good to ignore honest-to-god data. I would love to know how folks can get access to the data for study.
You are self-selecting for companies that would be willing to go through the bureaucracy to be vendors for you. Consequently, the type of people these companies would hire may not be of high quality. This may or may not be true for you, but is true in my experience.
So the type of customer you are attracts those type of devs.
Edit: this doesn't seem downvote worthy....
So the type of customer you are attracts those type of devs.
Edit: this doesn't seem downvote worthy....
Do you do any verification on how test focused they are? IME automated testing is like agile, the companies that talk the most are awful at the execution.
I'd completely believe that the automated testing companies were slower and more expensive, but I'd be inclined to blame the quality of the tests themselves. I've seen so many code bases where the tests slow down development and rarely catch errors, where you'll often have to spend more time decoding what the tests were supposed to be testing than the actual development. Even otherwise good developers can see testing as a necessary compliance item and will write awful tests just to get coverage up.
In your dataset are there any standout companies with low incident reports which do/don't have automated tests?
I'd completely believe that the automated testing companies were slower and more expensive, but I'd be inclined to blame the quality of the tests themselves. I've seen so many code bases where the tests slow down development and rarely catch errors, where you'll often have to spend more time decoding what the tests were supposed to be testing than the actual development. Even otherwise good developers can see testing as a necessary compliance item and will write awful tests just to get coverage up.
In your dataset are there any standout companies with low incident reports which do/don't have automated tests?
That's an interesting dataset and it aligns with my gut reaction: TDD (and testing in general) are ideal for bug fixes and code refactoring, which would be less useful when the software is going to be sold at a specific point in time (and therefore frozen or mostly frozen).
Any metrics on typescript vs vanilla js (assuming ya'll consume it:) ?
What about cost/time of fixing bugs? Any difference there?
One thing to consider I think is that TDD isn't just about the tests. It's also about architecting the software into small functions and lightweight classes, which are easy to write concise tests for and then implement incrementally. To TDD advocates, this resulting characteristic of the code is a valuable goal in itself, even just as a side effect of TDD.
Right, so as the author suggests, maybe TDD's real benefit is that it makes you think and plan a bit more before jumping into coding.
Therefore, we should have MDD - miniplan-driven-development: make a mini plan for the feature being developed, not so dissimilarly from what you would do with the first pass of TDD. The difference is, once you start implementing that plan and realize the problem is much different, you don't have to go back and keep modifying your original miniplan. You just do what you would normally do.
What you gain is probably a partial improvement in your development process without much cost.
Therefore, we should have MDD - miniplan-driven-development: make a mini plan for the feature being developed, not so dissimilarly from what you would do with the first pass of TDD. The difference is, once you start implementing that plan and realize the problem is much different, you don't have to go back and keep modifying your original miniplan. You just do what you would normally do.
What you gain is probably a partial improvement in your development process without much cost.
You may find A Discipline for Software Engineering by Watts Humphreys to be an interesting read.
My experience is that the resulting architecture will sometimes end up with characteristics that makes it easy to test but more complex, exposes things it should not and too many layers of indirection.
DHH wrote some about it here: https://dhh.dk/2014/test-induced-design-damage.html
I do like automated tests (unit and integration) and often TDD is appropriate. However tests are not the end goal of an architecture. The code should be maintainable, easy to follow and simple to reduce number of bugs. If TDD starts to change that by adding layers of indirection or changing the purpose of something just so you can do a fast unit test then something is wrong.
DHH wrote some about it here: https://dhh.dk/2014/test-induced-design-damage.html
I do like automated tests (unit and integration) and often TDD is appropriate. However tests are not the end goal of an architecture. The code should be maintainable, easy to follow and simple to reduce number of bugs. If TDD starts to change that by adding layers of indirection or changing the purpose of something just so you can do a fast unit test then something is wrong.
> It's really bad when doing anything that requires exploration and research
I wouldn't say that, I have an counterexample ([1]): It is clear what the refactoring (that is to be implemented) should do and how to state that ([2]), but it usually requires exploration and research how to work with the AST and which methods to use.
I would even say that TDD is awesome for exploring, researching, for getting a feeling of the problem's context, what to do and what the caveats are, as long as neither of that is required for stating the test itself.
Having tests first, you can simply start the debugger, try things out and with hot reloading you can write the code while running the specific test that you want to concentrate on. Visualization tools like [3] can greatly help exploring how to solve and implement the current test while you debug it.
[1] https://blog.hediet.de/post/implementing_typescript_refactor... [2] https://github.com/hediet/hediet-ts-refactoring-lsp/blob/mas... [3] https://marketplace.visualstudio.com/items?itemName=hediet.d...
I wouldn't say that, I have an counterexample ([1]): It is clear what the refactoring (that is to be implemented) should do and how to state that ([2]), but it usually requires exploration and research how to work with the AST and which methods to use.
I would even say that TDD is awesome for exploring, researching, for getting a feeling of the problem's context, what to do and what the caveats are, as long as neither of that is required for stating the test itself.
Having tests first, you can simply start the debugger, try things out and with hot reloading you can write the code while running the specific test that you want to concentrate on. Visualization tools like [3] can greatly help exploring how to solve and implement the current test while you debug it.
[1] https://blog.hediet.de/post/implementing_typescript_refactor... [2] https://github.com/hediet/hediet-ts-refactoring-lsp/blob/mas... [3] https://marketplace.visualstudio.com/items?itemName=hediet.d...
I don't typically tdd, but I'll say TDD is also awesome when you are in a crunch and working on some feature that has, say more than one dependency and more than say four corner cases and you are all amuddle about which one you should do first. Especially, london-style? Is it? Where you write out your trivial stub implementation first, helps me sort it out and not worry about thinking of everything.
He said that too, and sometimes is better to write the tests after you have the functionality finished and working because you know exactly what you expect and you add the tests to prevent feature updates to cause unexpected changes.
IMO TDD works if your input and output is clear from the start and the way to get the output is convoluted enough that you need the test.2
IMO TDD works if your input and output is clear from the start and the way to get the output is convoluted enough that you need the test.2
It is still useful, just a different kind of test.
High level quality/performance check, rather than testing functions. Produces values, not pass fail. Not really a unit test, an automated integration test of a module.
Simple test run to detect crashes or utter failures in CI fashion helps with speed of development too. Also not a unit test.
Once we had a research solution and were setting up performance improvements, we have put regression tests in place for the replaced functions and the whole system, derived from earlier module quality tests. Added a few well chosen property based unit tests.
This has caught edge cases in the fast implementations.
High level quality/performance check, rather than testing functions. Produces values, not pass fail. Not really a unit test, an automated integration test of a module.
Simple test run to detect crashes or utter failures in CI fashion helps with speed of development too. Also not a unit test.
Once we had a research solution and were setting up performance improvements, we have put regression tests in place for the replaced functions and the whole system, derived from earlier module quality tests. Added a few well chosen property based unit tests.
This has caught edge cases in the fast implementations.
We do the same at work. No unit tests, only integration and regression tests. See metamorphic tests (comparing outputs for mutated inputs).
One thing I've been trying out recently is adding asserts to code (design by contract): encode function preconditions, postconditions, invariants.
Now there are many more ways to "crash" the system while testing. The gist of it is: if you know that there is a bug if a particular condition happens, add an assert encoding this. Now all code that exercises the code with the assert automatically become tests.
I've found preconditions to be more useful than the other properties.
One thing I've been trying out recently is adding asserts to code (design by contract): encode function preconditions, postconditions, invariants.
Now there are many more ways to "crash" the system while testing. The gist of it is: if you know that there is a bug if a particular condition happens, add an assert encoding this. Now all code that exercises the code with the assert automatically become tests.
I've found preconditions to be more useful than the other properties.
No offence but I'm amazed you weren't using assertions (and assertions as pre/post conditions, invars) from the start. They work so well. And true, you get many new ways to blow up the code; all to good.
(Edit: pre.post/assertions/invars etc are what I've used in my own code. There's little push in most places I've worked for any testing, never mind anything systematic like this).
(Edit: pre.post/assertions/invars etc are what I've used in my own code. There's little push in most places I've worked for any testing, never mind anything systematic like this).
You're absolutely right. Assertions are so easy to use and there's no barrier to start using them. You can start small, one assertion at a time, no large refactorings required.
Thanks for taking it constructively!
For anyone reading this, I originally was taught assertions etc. at university but really got to use them after reading this ppt presentation by Tony Hoare (PDF here. Only took 1/2 hour to find, thanks for getting crappier, google).
Really recommended! http://www.cs.cornell.edu/courses/cs2110/2014sp/assignments/...
Honestly, it's short, please everyone give this 10 minutes of your time. It was one of the main things that started my move from rando programmer to something closer to engineering practice. I just wish companies I worked for gave a damn for it.
For anyone reading this, I originally was taught assertions etc. at university but really got to use them after reading this ppt presentation by Tony Hoare (PDF here. Only took 1/2 hour to find, thanks for getting crappier, google).
Really recommended! http://www.cs.cornell.edu/courses/cs2110/2014sp/assignments/...
Honestly, it's short, please everyone give this 10 minutes of your time. It was one of the main things that started my move from rando programmer to something closer to engineering practice. I just wish companies I worked for gave a damn for it.
Very well put. It is a great paradigm for problems that you understand very well.
But I think we can also define it more inclusive and still be fine: TDD is a good paradigm for programming against well defined APIs.
For example if you are handed an API specification then locking down your interface(s) with tests in advance can be very helpful.
What is even more helpful is to have a higher level language or abstraction that encodes the specification in detail and generates the tests for you (Clojure spec comes to mind).
edit: typo
But I think we can also define it more inclusive and still be fine: TDD is a good paradigm for programming against well defined APIs.
For example if you are handed an API specification then locking down your interface(s) with tests in advance can be very helpful.
What is even more helpful is to have a higher level language or abstraction that encodes the specification in detail and generates the tests for you (Clojure spec comes to mind).
edit: typo
TDD can work if the tests are integration tests and each test case covers an entire feature (one which can be clearly described using non-technical language). Integration tests only lock down the high level interfaces and behaviors so they allow you to keep reworking the guts of the system without ever having to rewrite the test cases.
Unit tests are mostly only good in the very final stages of the project when you have a fully working, essentially perfect, bug-free system and you just want to lock it all down so that nobody can make even the tiniest changes to the code without breaking all the tests and becoming insecure about their abilities in the face of such a remarkable code base.
If you're writing unit tests for poorly architected code, you're essentially locking down this horrible architecture and forcing all future developers to find complex ways to work around it instead of allowing them to confidently make the necessary restructurings to allow them to cleanly build on top (this kind of "I'm not breaking any features" confidence can only come from integration tests).
When it comes to complex systems, writing unit tests too early in the project is a bad idea; especially when combined with an agile development methodology. It's like building a skyscraper over several years and perfectly analysing every steel rod, every brick and every pane of glass as it is added to the structure but never actually stepping back to check that the structure as a whole is actually pointing upwards.
When it comes to complex systems, writing unit tests too early in the project is a bad idea; especially when combined with an agile development methodology. It's like building a skyscraper over several years and perfectly analysing every steel rod, every brick and every pane of glass as it is added to the structure but never actually stepping back to check that the structure as a whole is actually pointing upwards.
> He's right, but also wrong. It really depends on what you are developing.
The more useful thing to notice beyond TDD is how this is true of almost every development model and programming pattern (including the patterns built into languages that pretend they are not) - development processes and programming patterns are almost never generally applicable - The problems come when people who don't understand this attempt to apply them generally and blindly, e.g the classic go a read a patterns book or development strategy book and now everything is a nail for their preferred choice of hammer.
I'm not being defensive of TDD though, just because it's subjectively useful does not make it equal, to me TDD looks to have very narrow utility in general for the vast majority of projects it's going to get in the way.
The more useful thing to notice beyond TDD is how this is true of almost every development model and programming pattern (including the patterns built into languages that pretend they are not) - development processes and programming patterns are almost never generally applicable - The problems come when people who don't understand this attempt to apply them generally and blindly, e.g the classic go a read a patterns book or development strategy book and now everything is a nail for their preferred choice of hammer.
I'm not being defensive of TDD though, just because it's subjectively useful does not make it equal, to me TDD looks to have very narrow utility in general for the vast majority of projects it's going to get in the way.
Or a classic take from DHH 7 years ago, just test the big things:
https://signalvnoise.com/posts/3159-testing-like-the-tsa
Exactly! Well put.
Everything has a cost. TDD (and Refactoring) increases the cost of implementation (linearly), but they greatly reduce the cost of change. Without TDD (and refactoring) the cost of change might become exponential and impossible to catch up to.
Assuming that the amount of test code is 2-4x the amount of production code, TDD increases the cost of change by 2-4x when change is most likely to occur: at the beginning of development.
Likelihood of change and cost of change are different. A codebase which is very large is, all other facts held equal, much harder to change. While a small, early codebase may iterate very rapidly, drag will increase. The question is whether in the expected lifetime the higher upfront cost of providing tests pays off in average velocity.
Agreed, it increases linearly. But now think about the cost of change without tests. The longer you wait to introduce the change the more you will have to change (increases exponentially). If this code was fully tested and maybe refactored (isolated) when the need arises, the cost of change would almost go to 0 because you would only have to implement a new feature without touching the old code.
You assume that changing a software that has tests is free, which is wrong.
Your previous-to-last sentence applies equally to a software project with or without tests.
Your previous-to-last sentence applies equally to a software project with or without tests.
> If this code was fully tested and maybe refactored (isolated) when the need arises, the cost of change would almost go to 0 because you would only have to implement a new feature without touching the old code.
You don't even know the "change", you just assume that it will be a change that takes zero effort to implement, to satisfy your argument.
You don't even know the "change", you just assume that it will be a change that takes zero effort to implement, to satisfy your argument.
I don't really get what testing has to do with whether or not a piece of code is isolated or not? For example if you're making a change to a 4 line function with a clearly defined interface, the change is probably going to be trivial, regardless of whether the interface is defined by a set of unit tests or a short comment above the function declaration
The point is to have tests.
What came first the chicken or the egg?
Either the test came first and the code after or the code came first and test after.
An issue can arise in fast agile test driven development environments if you develop the code first and then do not get time to do the tests. If you start with the test you will be ensured to have time to write code otherwise the software will not work.
"The muscle doesn't see what you're holding in your hands." Arnold Schwarzenegge - The tests doesnt care how you got them in place
What came first the chicken or the egg?
Either the test came first and the code after or the code came first and test after.
An issue can arise in fast agile test driven development environments if you develop the code first and then do not get time to do the tests. If you start with the test you will be ensured to have time to write code otherwise the software will not work.
"The muscle doesn't see what you're holding in your hands." Arnold Schwarzenegge - The tests doesnt care how you got them in place
Requirements come before implementation.
In many organisations it often happens that the test team implements tests and is ready to test a feature before the dev team has actually implemented it.
IMO, that's the basis for TDD, really. When you start coding you should know what the result should be and thus you should write tests first to capture this and guide implementation.
In many organisations it often happens that the test team implements tests and is ready to test a feature before the dev team has actually implemented it.
IMO, that's the basis for TDD, really. When you start coding you should know what the result should be and thus you should write tests first to capture this and guide implementation.
I'm generally inclined to agree, test coverage is good, but test driven development is awkward. I think there's a tinkerer's mindset which is very much stifled by TDD.
I think TDD does shine for some things, it especially shines for refactors (where the tests ideally shouldn't change anyway) or bug-fixing where you can write in a test to catch the bug that has been found as a regression test before starting to fix the bug.
For brand new features it is a signifincant discomfort. I concede that that discomfort can result in more thought-through code but it can also just put off the implementer into not working as efficiently as they would be able to in a 'code first, then refactor' mindset.
I think TDD does shine for some things, it especially shines for refactors (where the tests ideally shouldn't change anyway) or bug-fixing where you can write in a test to catch the bug that has been found as a regression test before starting to fix the bug.
For brand new features it is a signifincant discomfort. I concede that that discomfort can result in more thought-through code but it can also just put off the implementer into not working as efficiently as they would be able to in a 'code first, then refactor' mindset.
On the flip side, "code first, then refactor" is only safe if you have tests to confirm the validity of the refactor, and in my experience, a TDD mindset is the only thing that ensures I have thorough tests by the time I need to refactor.
That said, it sounds like my version of TDD may be different than a lot of others. The tests I write before coding tend to test real-world logic and requirements, in terms of the domain language, rather than testing implementation. This means I can refactor everything behind that DSL-like facade and my tests give me assurance that I haven't changed the logic.
If your tests are at the implementation level, I can see how a TDD approach would impede refactoring and eliminate tinkering. If refactoring the code means rewriting the tests, then your tests aren't protecting you, they're just getting in the way.
That said, it sounds like my version of TDD may be different than a lot of others. The tests I write before coding tend to test real-world logic and requirements, in terms of the domain language, rather than testing implementation. This means I can refactor everything behind that DSL-like facade and my tests give me assurance that I haven't changed the logic.
If your tests are at the implementation level, I can see how a TDD approach would impede refactoring and eliminate tinkering. If refactoring the code means rewriting the tests, then your tests aren't protecting you, they're just getting in the way.
TDD is less about writing tests and more about the approach.
Just having an understanding of TDD and holding it as an aim will ultimately result in a better, more maintainable codebase.
So what's the downside?
Just having an understanding of TDD and holding it as an aim will ultimately result in a better, more maintainable codebase.
So what's the downside?
TDD is an interesting concept.
Anything you write as an engineer has to be tested. Manual testing is way slower than automated testing.
I find that when I have a few good automated tests in place, especially in browser selenium tests, I save literally days of work of manual testing. Thats time that I can use to build more features, get more feedback on my product or do other more productive things than manual testing.
10 minutes of time writing a good test saves me days of work in the future testing new changes. Writing good tests is a high impact, time saving investment.
Anything you write as an engineer has to be tested. Manual testing is way slower than automated testing.
I find that when I have a few good automated tests in place, especially in browser selenium tests, I save literally days of work of manual testing. Thats time that I can use to build more features, get more feedback on my product or do other more productive things than manual testing.
10 minutes of time writing a good test saves me days of work in the future testing new changes. Writing good tests is a high impact, time saving investment.
Manual testing is way slower than automated testing.
It’s entirely a matter of perspective. I consider writing a unit test to do something the compiler could check for you if you were using a statically-typed language to be “manual testing”.
It’s entirely a matter of perspective. I consider writing a unit test to do something the compiler could check for you if you were using a statically-typed language to be “manual testing”.
Manual testing is where you click buttons on a device and observe results. Even that can be automated most of the time.
Pointless unit testing is a separate thing.
Pointless unit testing is a separate thing.
I feel this is an unintentional false dichotomy caused by the name "test-driven". An alternative might be automatic-verification-driven or something like it.
Basically I want the computer to automatically point out errors, and I want to prove that it will do so by prompting that error detection first. Whether that's by types or test cases is secondary.
Personally I prefer types to test cases for many purposes (a good type system sweeps away a lot of toil in my experience), but I will use whatever tools a given ecosystem gives me in the mix that makes sense for that ecosystem.
Basically I want the computer to automatically point out errors, and I want to prove that it will do so by prompting that error detection first. Whether that's by types or test cases is secondary.
Personally I prefer types to test cases for many purposes (a good type system sweeps away a lot of toil in my experience), but I will use whatever tools a given ecosystem gives me in the mix that makes sense for that ecosystem.
Absolutely, but testing is not what the author is opposed to. He's arguing against writing tests before writing the code that gets tested.
> A great idea hiding behind a terrible implementation
TDD is a method.
TDD forces you be clear about what the result of your code should be before you start coding. It also ensures that there is a test to check your code. This is certainly not dumb.
You will write tests anyway (right?) so it does seem smarter and more effective to write them first in the same way as you write requirements first before writing code. Nothing prevents you from iterating as progress and discover corner cases, for example.
People who say that TDD moves slower are simply admitting that they don't test. Automated tests are also crucial because 99% of testing is regression testing and that obviously cannot be done manually every time the code changes.
I found it rather ironic that the article ends by praising behaviour-driven development, which is an extension of TDD...
TDD is a method.
TDD forces you be clear about what the result of your code should be before you start coding. It also ensures that there is a test to check your code. This is certainly not dumb.
You will write tests anyway (right?) so it does seem smarter and more effective to write them first in the same way as you write requirements first before writing code. Nothing prevents you from iterating as progress and discover corner cases, for example.
People who say that TDD moves slower are simply admitting that they don't test. Automated tests are also crucial because 99% of testing is regression testing and that obviously cannot be done manually every time the code changes.
I found it rather ironic that the article ends by praising behaviour-driven development, which is an extension of TDD...
> TDD forces you be clear about what the result of your code should be before you start coding
... which is often difficult and inefficient. A large part of the point of the article is that when making changes to an existing system, you often DON'T know until doing some experimentation what the result of your particular new bit of code should be. You know what change you want to happen to the behaviour of the system as a whole, but don't yet understand how the pieces that make up the system slot together. That permits you to dive in and try making changes and see what their effect is, but doesn't permit you to write a unit test right away.
> it is smarter and more effective to write them first.
But... why? You're asserting this without any justification.
> People who say that TDD moves slower are simply admitting that they don't test.
This accusation is pretty tedious. The article was explicitly comparing the test-first-code-second approach against the code-first-test-second approach and giving a reasoned argument (which you've not acknowledged or engaged with) for why the second was usually superior. The author isn't saying they don't test or arguing for not testing.
> I found it rather ironic that the article ends by praising behaviour-driven development
That was sarcasm.
... which is often difficult and inefficient. A large part of the point of the article is that when making changes to an existing system, you often DON'T know until doing some experimentation what the result of your particular new bit of code should be. You know what change you want to happen to the behaviour of the system as a whole, but don't yet understand how the pieces that make up the system slot together. That permits you to dive in and try making changes and see what their effect is, but doesn't permit you to write a unit test right away.
> it is smarter and more effective to write them first.
But... why? You're asserting this without any justification.
> People who say that TDD moves slower are simply admitting that they don't test.
This accusation is pretty tedious. The article was explicitly comparing the test-first-code-second approach against the code-first-test-second approach and giving a reasoned argument (which you've not acknowledged or engaged with) for why the second was usually superior. The author isn't saying they don't test or arguing for not testing.
> I found it rather ironic that the article ends by praising behaviour-driven development
That was sarcasm.
If you start coding before knowing what you are implementing then you have a bigger problem than TDD.
Experimentation is not the same as implementation, by the way.
Obviously nothing is adhered to 100% of the time in real life, this is not a dogma, but the point that you should know what the result of your code should be before you write it and should thus write tests first (which can also help you clarify your understanding) is eminently reasonable and valid.
> That was sarcasm.
Article is poor overall. Sarcasm does not help.
Experimentation is not the same as implementation, by the way.
Obviously nothing is adhered to 100% of the time in real life, this is not a dogma, but the point that you should know what the result of your code should be before you write it and should thus write tests first (which can also help you clarify your understanding) is eminently reasonable and valid.
> That was sarcasm.
Article is poor overall. Sarcasm does not help.
> If a coding style turns out to be great in theory but not practice, let’s keep the parts that work and toss the rest. My convoluted point is: There are lots of ways to code, we need to stop holding any one of them up as the “best” way.
I think this is the crux of what the authour is trying to say. Not necessarily a criticism of TDD, but rather a criticism of holding to a particular belief no matter the circumstances. Of being inflexible.
I think this is the crux of what the authour is trying to say. Not necessarily a criticism of TDD, but rather a criticism of holding to a particular belief no matter the circumstances. Of being inflexible.
I don't disagree with being flexible when needed but the counterargument is that flexibility can sometimes be used as an argument for corner cutting. For example when you start to make a few exceptions for TDD it then becomes easier to make more exceptions; if you're not careful you can quickly end up in a situation where your rational is "we don't have time to write tests" or worse yet "can't be bothered to". The point of methodologies like TDD is they force people to follow the best practices even when it's easier not to simply by mandating a standard process.
> The point of methodologies like TDD is they force people to follow the best practices even when it's easier not to simply by mandating a standard process.
I don't disagree with that, and I don't think the authour disagrees with that.
It's when the mandated process interferes with working in the actual world.
A better test-pipeline in the article's example might be, "We don't merge without full test coverage of changes" rather than "We must have a test before we've explored how a spec should look".
If the standard makes the real world overly difficult, then it will cause people to try and cut corners. It makes the developer seek to do the wrong thing.
There's nothing inherently wrong with TDD or a bunch of other processes. There is a problem if you're pushing yourself into a corner where you find yourself fighting the process rather than solving the task that needs solving.
I don't disagree with that, and I don't think the authour disagrees with that.
It's when the mandated process interferes with working in the actual world.
A better test-pipeline in the article's example might be, "We don't merge without full test coverage of changes" rather than "We must have a test before we've explored how a spec should look".
If the standard makes the real world overly difficult, then it will cause people to try and cut corners. It makes the developer seek to do the wrong thing.
There's nothing inherently wrong with TDD or a bunch of other processes. There is a problem if you're pushing yourself into a corner where you find yourself fighting the process rather than solving the task that needs solving.
> A better test-pipeline in the article's example might be, "We don't merge without full test coverage of changes" rather than "We must have a test before we've explored how a spec should look".
This is very much the rule I prefer to enforce as well. Though I do really like the TDD approach when there are defined specifications or refactoring happens. In those situations it can sometimes even speed up development because once the tests are in place you then have a tighter "write, test, repeat" cycle.
However I do still agree with all the points you've raised.
This is very much the rule I prefer to enforce as well. Though I do really like the TDD approach when there are defined specifications or refactoring happens. In those situations it can sometimes even speed up development because once the tests are in place you then have a tighter "write, test, repeat" cycle.
However I do still agree with all the points you've raised.
We start with hard "every module must have an end-to-end test" generally. This is a good level. Add tests as needed for debugging issues.
Lately I've hit some joker boss who thinks TDD can be done without automated tests. :(
The tests are semi manual (scripted), relatively slow to execute and a development bottleneck as the test machines are few. Some other jokers devs ignored even this limited testing and obvious breakage results.
Lately I've hit some joker boss who thinks TDD can be done without automated tests. :(
The tests are semi manual (scripted), relatively slow to execute and a development bottleneck as the test machines are few. Some other jokers devs ignored even this limited testing and obvious breakage results.
I have learned and used TDD before, but I don't do TDD. I am, however glad I learned it, as it influences the way I write code now to the better. (Think more before I start writing, for instance, and writing smaller testable units of code up front). Much in the same way learning a new programming language/paradigm also can change how you write code in the old language.
The authors of this might not realize it, but a good chunk of their audience can't read their post at all, due to Medium's paywall.
Regardless of my opinion on the topic, which I don't have:
why must software engineering be mainly opinion-based? Why can't we have objective facts, or at least only talk about objective facts without going out asserting one's opinions as truth?
AFAIK other engineering disciplines do not suffer from this problem as much as software engineering. This really bugs me.
why must software engineering be mainly opinion-based? Why can't we have objective facts, or at least only talk about objective facts without going out asserting one's opinions as truth?
AFAIK other engineering disciplines do not suffer from this problem as much as software engineering. This really bugs me.
Because software projects fail for people reasons, and people reasons are usually subjective.
If you have a tight team of experienced devs building a simple CRUD app you can do almost anything short of building the thing in Polish BASIC with triple spaced lines, and you'll still get a result. Likewise if you have a team with 8 managers and your best dev has only done a couple of courses on codecademy, no set of engineering approaches is going to save you.
And that's just the factors within the engineering team. For every inexperienced team that doesn't deliver a result, there's 10 teams that are gutted from internal politics or management decisions, and 100 startups that fail to find a market fit. On the flip side of that, every month or so I find either a showstopping bug or a new puzzler of a UX decision in one of Uber's products, but it literally has no bearing on their success as a company. The simple fact is it doesn't matter whether they do TDD, or scrum, or whatever, as long as they don't do anything truly catastrophic.
Basically, the majority of success factors for the majority of projects come from outside the engineering team. And the ones that don't will be dominated by the team's basic development skills, which makes the signal much worse for measuring the effectiveness of anything from a project management, high level architecture, or testing perspective.
If you have a tight team of experienced devs building a simple CRUD app you can do almost anything short of building the thing in Polish BASIC with triple spaced lines, and you'll still get a result. Likewise if you have a team with 8 managers and your best dev has only done a couple of courses on codecademy, no set of engineering approaches is going to save you.
And that's just the factors within the engineering team. For every inexperienced team that doesn't deliver a result, there's 10 teams that are gutted from internal politics or management decisions, and 100 startups that fail to find a market fit. On the flip side of that, every month or so I find either a showstopping bug or a new puzzler of a UX decision in one of Uber's products, but it literally has no bearing on their success as a company. The simple fact is it doesn't matter whether they do TDD, or scrum, or whatever, as long as they don't do anything truly catastrophic.
Basically, the majority of success factors for the majority of projects come from outside the engineering team. And the ones that don't will be dominated by the team's basic development skills, which makes the signal much worse for measuring the effectiveness of anything from a project management, high level architecture, or testing perspective.
Well call me crazy, but imho the reason for that is that for the most part, software engineering is not engineering. We're not fighting laws of nature, we're fighting other people's style and decisions. That's why our work is opinion based: we're basically computer lawyers.
I can't agree with this. We are fighting with chaos, we organize and encode processes, systems and information.
This is the definition of engineering on wikipedia and we fit the description:
> Engineering is the creative application of science, mathematical methods, and empirical evidence to the innovation, design, construction, operation and maintenance of structures, machines, materials, devices, systems, processes, and organizations.
This is the definition of engineering on wikipedia and we fit the description:
> Engineering is the creative application of science, mathematical methods, and empirical evidence to the innovation, design, construction, operation and maintenance of structures, machines, materials, devices, systems, processes, and organizations.
Software engineering may not be an engineering discipline but in theory you could set up empirically studies/experiments to test certain hypotheses of software development practices. In theory you could also review or evaluate design against certain criteria and derive what's better to fulfill certain goals.
And yet, when the subject boils down to people and culture, testing is slow, complicated and unrewarding. Results need a lot of variable elimination and are rarely used for practical decision making. This applies to most “people” subjects.
Testing nature is much easier, and thus establishing norms in these subjects is easier.
Testing nature is much easier, and thus establishing norms in these subjects is easier.
Absolutely. And I think there were actually studies on the effectiveness of TDD, and I seem to recall them confirming it.
[deleted]
[deleted]
You are so right, the laws of nature have been abstracted
> we're basically computer lawyers
I like this. I mean, as a description, not so much as a fact, but it is what it is :D
I like this. I mean, as a description, not so much as a fact, but it is what it is :D
I think the question is easier to answer if it's flipped. Why can't other engineering disciples work fast-and-loose?
The answer is that for software engineering, the cost balance between "working fast" and "avoiding errors" largely works out in favour of "working fast", even with the potential error rates factored in. In other engineering disciplines, the cost of failure is higher (often much higher), and therefore "slow and steady, avoiding errors" methodologies win out in this balance.
The answer is that for software engineering, the cost balance between "working fast" and "avoiding errors" largely works out in favour of "working fast", even with the potential error rates factored in. In other engineering disciplines, the cost of failure is higher (often much higher), and therefore "slow and steady, avoiding errors" methodologies win out in this balance.
There is a good amount of research on software engineering, I love love love "Making Software: What Really Works, and Why We Believe It" by Andy Oram, as it demonstrates the non-opinion-based way of thinking about software engineering. And has some really interesting insights to boot.
Two points.
First, software "engineering" is not an engineering discipline. You might as well call novel writing "literary engineering", but calling it that won't make it true.
Second, the 10x software developer is very much real. People try to ascribe their performance to this or that technology or methodology, but in reality what makes a 10x engineer is a special psychological predilection, not their tools.
First, software "engineering" is not an engineering discipline. You might as well call novel writing "literary engineering", but calling it that won't make it true.
Second, the 10x software developer is very much real. People try to ascribe their performance to this or that technology or methodology, but in reality what makes a 10x engineer is a special psychological predilection, not their tools.
Because this is really project management not software engineering. You would get into real arguments about how to micro manage a team of engineers designing a space shuttle replacement. Complex expensive tasks with real tradeoffs don’t have simple answers.
As I have more and more experience in the software development field, the more I think it is not engineering, but rather art. At least it's a creative process, not always an exact science.
That's because there are too many developers with the title of senior but skills of junior, and a business person can't tell which one is which unless they're one of the few high experienced developers out there.
The only time where a business person knows they hired the wrong people is when people claim for a rewrite. At that point, sorry, it's too late.
The only time where a business person knows they hired the wrong people is when people claim for a rewrite. At that point, sorry, it's too late.
Probably because we are dancers, after all.
It seems to me that software tests is like checking if an architectural design is structurally stable.
It's dumb to do that when you still don't have the characteristics of the space where you are building or the materials available, but it's dumb not to do it when you know exactly what and how you are building it.
In the same way, it's dumb not to do it when you have already a building and you are going to start to change things.
I think the problem is that, being all information, in programing those phases look the same but they are actually very different.
It's dumb to do that when you still don't have the characteristics of the space where you are building or the materials available, but it's dumb not to do it when you know exactly what and how you are building it.
In the same way, it's dumb not to do it when you have already a building and you are going to start to change things.
I think the problem is that, being all information, in programing those phases look the same but they are actually very different.
In my experience, if you find that you're unable to do TDD with a problem you're trying to solve, then you've probably not decomposed the problem enough. In your mind. Step back. Think.
The rush to produce code, now, is making working in this industry suck.
The rush to produce code, now, is making working in this industry suck.
What I keep running across, in different companies, different domains, different engineering styles is code that was written first with the intent to add code later... that ends up being untestable. It seems to be a common “design pattern” (in Java, at least) to add a Singleton that connects to a data store and reference that Singleton everywhere in the codebase - which means that using any of the code triggers a static method that tries to connect to remote Mongo/Cassandra/Postgres/Redis/something.
I find that writing _something_ can help me to get a feel for a problem. Start, then sitting back and thinking about it, helps me to move towards a better solution faster.
Of course, I don't always do the stopping and thinking part...
Of course, I don't always do the stopping and thinking part...
> I find that writing _something_ can help me to get a feel for a problem. Start, then sitting back and thinking about it, helps me to move towards a better solution faster.
That summarizes the struggle that I have with TDD. I guess you could argue that I’m doing TDD wrong, but most of the time I feel like I don’t know what I’m going to be writing until I write it.
Basically most of my coding I feel like I’m prototyping until I iterate a few times and arrive at a solution I’m happy with and understand where the boundaries between various functions need to be. Until then, how am I supposed to pre-empt my solution with tests?
That summarizes the struggle that I have with TDD. I guess you could argue that I’m doing TDD wrong, but most of the time I feel like I don’t know what I’m going to be writing until I write it.
Basically most of my coding I feel like I’m prototyping until I iterate a few times and arrive at a solution I’m happy with and understand where the boundaries between various functions need to be. Until then, how am I supposed to pre-empt my solution with tests?
> The rush to produce code, now, is making working in this industry suck.
Who wants to think, when you can code, right?
Who wants to think, when you can code, right?
What works perfectly for some devs doesn’t for others. That why there are choices.
IMHO only thing dumb is developing without testing
IMHO only thing dumb is developing without testing
TDD is one tool in your toolbox. You can easily solve problems like this one: https://itnext.io/you-dont-know-tdd-691efe670094.
However, there's a myriad of other problems TDD doesn't help you, like when you need to design a system beforehand or you want to make an educated jump to a solution that's good enough and you already know it.
However, there's a myriad of other problems TDD doesn't help you, like when you need to design a system beforehand or you want to make an educated jump to a solution that's good enough and you already know it.
I am more a fan of behaviour driven where the behaviours are written using specflow or cucumber almost like acceptance tests. Then the developer writes code but the behaviours are validated by the business analyst or product owner
Development is the ability to deliver/ship the things that increase your business metrics, consistently.
Sometimes the right thing to do is TDD, sometimes the right thing to do is to ssh into a production server and modify a Perl script.
Sometimes the right thing to do is TDD, sometimes the right thing to do is to ssh into a production server and modify a Perl script.
As with most software engineering tools and practices, the context matters.
I'd imagine that TDD is good when you know exactly what the requirement that the project has. i.e. TDD is good in the implementation phase but not the design phase. In the design phase, you often don't know exactly what the problem really is, so you need to keep things as loose as possible because you're going to experiment. I imagine that in many small business scenarios these two phases are often fused together, so TDD wouldn't appeal that much for them.
I'd imagine that TDD is good when you know exactly what the requirement that the project has. i.e. TDD is good in the implementation phase but not the design phase. In the design phase, you often don't know exactly what the problem really is, so you need to keep things as loose as possible because you're going to experiment. I imagine that in many small business scenarios these two phases are often fused together, so TDD wouldn't appeal that much for them.
After 15 years in technology/software development my impression is that your favorite methodology says more about you than anything else.
The sharpest engineers I know distinguish themselves mostly by how rarely they resort to running code at all. Instead they seem to have a mental model of the code base they are working on, similar to that of a mathematician. They can write code for days, weeks (or even months) and just know it will mostly work once they run it.
The sharpest engineers I know distinguish themselves mostly by how rarely they resort to running code at all. Instead they seem to have a mental model of the code base they are working on, similar to that of a mathematician. They can write code for days, weeks (or even months) and just know it will mostly work once they run it.
Did anyone, ever, in the history of world coded for months without running the code?
There clearly are problems that are suited very well for TDD and others that aren't.
I guess the suitability of TDD depends on how much a feature involves "how" rather than "what": Whenever it is clear what the feature should do (and what the feature's interface looks like) and the implementation is only about the "how", TDD seems to a very good idea. Almost every compiler-related task falls into this category. I just wrote a blog article on how to implement Typescript refactorings using TDD ([1]) and I don't think anyone could argue against using TDD there.
If the feature is more about "what" (like UI/UX), TDD seems to be more of a burden than an useful asset.
[1] https://blog.hediet.de/post/implementing_typescript_refactor...
I guess the suitability of TDD depends on how much a feature involves "how" rather than "what": Whenever it is clear what the feature should do (and what the feature's interface looks like) and the implementation is only about the "how", TDD seems to a very good idea. Almost every compiler-related task falls into this category. I just wrote a blog article on how to implement Typescript refactorings using TDD ([1]) and I don't think anyone could argue against using TDD there.
If the feature is more about "what" (like UI/UX), TDD seems to be more of a burden than an useful asset.
[1] https://blog.hediet.de/post/implementing_typescript_refactor...
This is skipping the purpose of TDD actually, TDD is basically binding your every code change to a test (basically it is a spec) You are supposed to write the minimum required code to satisfy a failing test. Basically it is kind of commenting every bit of your code with a test.
So every line of code you are writing has to have a purpose, and later on when you are fixing a bug or adding something new, you are making sure, you didn’t break any previous functionality.
So every line of code you are writing has to have a purpose, and later on when you are fixing a bug or adding something new, you are making sure, you didn’t break any previous functionality.
And yet when an oracle dev comments on HN about the test suite we all gasp in horror...
"...I never understood why it was better to do things backwards...The idea behind TDD is that you’re able to write a test because you sit down and think about things first...."
Yeah no. You have been instructed poorly. It's not your fault.
Yes, you have to think about things, but that's not the real purpose of TDD. Just like making a good design, it's a side effect.
Straight coding is doing it backwards, as odd as that sounds. The reason is that the computer never lies, but it's really, really easy to lie to yourself, forget things, misunderstand your own variable names, and so on. When you're coding, you'll make all kinds of errors. The computer will not. So wouldn't it be better to have the computer constantly checking on you to see if you're making any new errors? Better still, not only will it check on you, it'll check on everybody else who touches the code too.
There are domains in which TDD does not make sense. Exploratory coding, like you'd do in startups, for instance. Small pure functional code. Academic learning. In each of these cases you are still doing TDD, it's just you're not coding the tests. You never get away from TDD, you just sometimes hide it or pretend it isn't happening. There's a test, it fails, you write code to make it pass.
In other cases, such as any non-trivial mutable OO commercial code that is going to be around for a while, not using TDD is malpractice. Whatever small hit you may take on initial productivity is insignificant compared to the endless amount of money you may spend later on maintenance.
Plus, I'm not so sure it's inefficient to begin with. Instead, I think a lot of coders code in an inefficient way writing code that is difficult or impossible to test. Once you start using TDD, you're going to have to come to terms with that and un-fuck your code. That's probably going to suck. Best to do it earlier rather than later. (Long discussion here about what to do with legacy codebases)
Yeah no. You have been instructed poorly. It's not your fault.
Yes, you have to think about things, but that's not the real purpose of TDD. Just like making a good design, it's a side effect.
Straight coding is doing it backwards, as odd as that sounds. The reason is that the computer never lies, but it's really, really easy to lie to yourself, forget things, misunderstand your own variable names, and so on. When you're coding, you'll make all kinds of errors. The computer will not. So wouldn't it be better to have the computer constantly checking on you to see if you're making any new errors? Better still, not only will it check on you, it'll check on everybody else who touches the code too.
There are domains in which TDD does not make sense. Exploratory coding, like you'd do in startups, for instance. Small pure functional code. Academic learning. In each of these cases you are still doing TDD, it's just you're not coding the tests. You never get away from TDD, you just sometimes hide it or pretend it isn't happening. There's a test, it fails, you write code to make it pass.
In other cases, such as any non-trivial mutable OO commercial code that is going to be around for a while, not using TDD is malpractice. Whatever small hit you may take on initial productivity is insignificant compared to the endless amount of money you may spend later on maintenance.
Plus, I'm not so sure it's inefficient to begin with. Instead, I think a lot of coders code in an inefficient way writing code that is difficult or impossible to test. Once you start using TDD, you're going to have to come to terms with that and un-fuck your code. That's probably going to suck. Best to do it earlier rather than later. (Long discussion here about what to do with legacy codebases)
I find myself TDDing code when the problem space is well-defined, i.e. I know exactly what output I'm looking for. Last time I remember using it was, oddly, in making a game. I wanted to build a CLI 2048 clone. Specifying that was easy and fun.
About the only time I consistently code the test first is to reproduce defects. It's really useful in that case. Sometimes that also works for features.
When designing an interface I like to write usage examples. They're more nimble to work with than tests who require scaffolding. The usage examples do tend to become tests during implementation.
When designing an interface I like to write usage examples. They're more nimble to work with than tests who require scaffolding. The usage examples do tend to become tests during implementation.
Write the least amount of code that will solve the problem, then write the least amount of code that will make the feature as efficient as possible to your ability.
I concur! Additionally to the article I believe the overall problem with software development is that it cannot be done by everyone. Developing great software requires the mentality of a passionate artist and a lifetime dedication. Unfortunately most companies I've worked with (with very few exceptions) are only after immediate profit and thus creating toy programs mainly by means of integration of ready-made third party libraries. The example they set for new developers is catastrophic. Fewer and fewer people dwelve into the depths of knowledge. Shallow integration, adoption of over-hyped immature components and the new trend of containerization is a two-fold failure: a) Failure of educating minds to think and b) low quality end products for the users with all the consequences this brings (aka performance, security, UX, etc). It really feels as if software development has entered a dark era where instead of educating people we create mechanics that take 'experinments' to market asap and disguising them to look like they operate error-free. Of course such tactics cannot keep problems hidden forever. If only I could share with you the stories of large heap fragmentation I've heard over the years on production server code...
TDD is not dumb, just there are use cases where it fits better, specifically, when you know the exact inputs and outputs beforehand and how it will fit in your system. When designing an API, it's not a good use-case for TDD at all. The author obviously doesn't understand that.
If you don't even know what functions will you need, you obviously can't write a test for it!
Kent Beck, DHH and Martin Fowler explain it very nicely in the "Is TDD Dead?" dicussion: https://martinfowler.com/articles/is-tdd-dead/
I highly recommend it to everyone even if you think you understand what is TDD all about! It's a very deep, interesting discussion about TDD between truly great minds.
Kent Beck, DHH and Martin Fowler explain it very nicely in the "Is TDD Dead?" dicussion: https://martinfowler.com/articles/is-tdd-dead/
I highly recommend it to everyone even if you think you understand what is TDD all about! It's a very deep, interesting discussion about TDD between truly great minds.
What’s far easier is writing your code, manually doing some QA tests, and then writing automated tests that mimic those situations, specifically for the code you wrote.
This is the most popular method of doing things in my experience and the reason for that seems to be it makes chronological sense to a human brain. It’s very unnatural for people (including clever devs) to consider a project like manufacturing a car and starting with ‘the tire pressure should be correct’. Also too often (wrongly or rightly) prototypes often don’t have tests and that sets the tone quite early. Automated tests should be written ASAP no matter which methodology is used.
This is the most popular method of doing things in my experience and the reason for that seems to be it makes chronological sense to a human brain. It’s very unnatural for people (including clever devs) to consider a project like manufacturing a car and starting with ‘the tire pressure should be correct’. Also too often (wrongly or rightly) prototypes often don’t have tests and that sets the tone quite early. Automated tests should be written ASAP no matter which methodology is used.
At $DAYJOB, I find it easier to write the backend code, then write automated tests, then hook it up to the front end. Only at that point could I even try to manually QA the functionality, so adding tests while adding the API is just more natural.
The lesson I take away is that clearly delineated layers in the architecture gives more opportunities for natural test oriented coding, so it's worth thinking about layers in your prototypes and their early evolution.
Luckily common frameworks and patterns are usually layered already. SPA -> API is a pretty common layering, but within the SPA, you could have views -> vuex stores -> an api client layer etc. Your API could have views -> models, etc.
The lesson I take away is that clearly delineated layers in the architecture gives more opportunities for natural test oriented coding, so it's worth thinking about layers in your prototypes and their early evolution.
Luckily common frameworks and patterns are usually layered already. SPA -> API is a pretty common layering, but within the SPA, you could have views -> vuex stores -> an api client layer etc. Your API could have views -> models, etc.
This type of order will most probably get the developer into confirmation bias: writing the tests that show the code works.
The best for me is to thing about how would I test if the solution will work, then implement the solution and then run the tests. This why I try to compensate a little for comfirmation bias.
The best for me is to thing about how would I test if the solution will work, then implement the solution and then run the tests. This why I try to compensate a little for comfirmation bias.
That’s no so bad since automation is highly useful for regression testing.
TDD is just another tool. I don't use it all that often but there are some situations where I know it works. I have for example found it very helpful in verifying and later addressing issues in larger codebases. There are other approaches but they often make the root cause or causes of an issue harder to locate. I really hope the author reevaluates TDD as I think they're doing themselves a massive disservice.
One claim TDD makes is that a reasonable architecture arises from from its basic approach. To me this is an extraordinary statement of which I have seen no proof.
TDD doesn't make that claim, because TDD is not a thing which can make claims. Some people make that claim about TDD. Those people are indeed mistaken.
As someone who thinks TDD is useful, i find those people particularly infuritating, because such an obviously silly and easily disproven claim turns the programming public off TDD for no good reason.
As someone who thinks TDD is useful, i find those people particularly infuritating, because such an obviously silly and easily disproven claim turns the programming public off TDD for no good reason.
It is implied by the minimalism of the red-green-refactor mantra.
I don't think saying anything negative about test driven development is a positive contribution. Our industry should practice it more instead of less. I do it almost all the time. Sure, there are a few exceptions. It is quite unneeded for at throw-away script, obviously. If something is in a user interface and it is purely visual it may be better to write the code first because the browser in your head might not be good enough to write a correct test beforehand. Those are the exceptions, though. For any program containing somewhat complex logic TDD is king. There is nothing that beats it in terms of reliability and after some time also regarding speed because in the end nothing costs more time than something that keeps breaking in production. Thorough manual testing is also quite expensive in terms of time.
I note some people here are talking about things that require exploration and research as a counter-inducation. Well, maybe in some cases but certainly not in all. One could also start with a test at a relatively high level and then do the exploration while writing code to make it pass. In that case one would write more code to make it pass than would be normal but it still benefits from being in the TDD cycle. After having it basically working one does additional TDD cycles to iron out the cases where it would go wrong.
The main benefits of starting out with a test is that: 1) tests do cost time so you need to recoup that by going faster in other parts of development. If you start out with the test it immediately starts paying back when it flags your first attempt at an implementation as either passing or failing. 2) The fact that the test first should fail and fail in a particular way tells you whether your thinking about how the system works is actually correct. It is like bringing the scientific method to programming. People in practice very often have just the wrong idea of how something works in the first place.
People are also talking about TDD being a strange order to think about programming. This is also my experience. It requires some getting used to. It is quite good though. The point being that it enables one to not need to think about everything at the same time. When writing a test you think about the functionality you need. When writing an implementation you think about algorithms and when refactoring you think about code quality. In traditional development this gets rolled up in one big ball of mud which makes the thinking about either of these three aspects of lower quality.
One thing that people get into trouble with is trying to write test for functionality that is too low level and therefore very much implementation defined and therefore subject to change. I think one should generally work at a level where one tests the behavior of a cluster of a few classes. This problem also leads to tests that are too trivial. If one has a method that adds n to m and one writes a test for that one is testing that the processor really can add numbers and that is not very interesting.
I note some people here are talking about things that require exploration and research as a counter-inducation. Well, maybe in some cases but certainly not in all. One could also start with a test at a relatively high level and then do the exploration while writing code to make it pass. In that case one would write more code to make it pass than would be normal but it still benefits from being in the TDD cycle. After having it basically working one does additional TDD cycles to iron out the cases where it would go wrong.
The main benefits of starting out with a test is that: 1) tests do cost time so you need to recoup that by going faster in other parts of development. If you start out with the test it immediately starts paying back when it flags your first attempt at an implementation as either passing or failing. 2) The fact that the test first should fail and fail in a particular way tells you whether your thinking about how the system works is actually correct. It is like bringing the scientific method to programming. People in practice very often have just the wrong idea of how something works in the first place.
People are also talking about TDD being a strange order to think about programming. This is also my experience. It requires some getting used to. It is quite good though. The point being that it enables one to not need to think about everything at the same time. When writing a test you think about the functionality you need. When writing an implementation you think about algorithms and when refactoring you think about code quality. In traditional development this gets rolled up in one big ball of mud which makes the thinking about either of these three aspects of lower quality.
One thing that people get into trouble with is trying to write test for functionality that is too low level and therefore very much implementation defined and therefore subject to change. I think one should generally work at a level where one tests the behavior of a cluster of a few classes. This problem also leads to tests that are too trivial. If one has a method that adds n to m and one writes a test for that one is testing that the processor really can add numbers and that is not very interesting.
I agree that writing tests before code is unrealistic, but love tdd. We have nice weekends because of tdd.
TDD of course forces you to build modular mockable code. For me it encourages a short term thinking, hacking approach. I think it elevates unit testing a bit too far conceptually, but it does encourage better construction. Like the author implies, it's a useful way to think, even if you dont do it.
My experience is that tdd only works when the requirements are super clear
Testability, Performance, Readability, Maintainability are all vectors we can judge software by, and while they are not orthogonal, they are also rarely colinear. TDD optimizes on Testability to the expense of the others. This is rarely a good idea.
It's painful when I come to a project and the process for developing a feature is...
I think TDD at the very least is a education/comprehension exercise in abstract thinking which will discourage scenarios like the one described above. Once someone is able to TDD and 'gets it' then sometimes the way they approach arranging code even without TDD is better. I think this is why we may have mixed messages like "TDD is great!.. but we don't practice it at work."
Using a test harness any sorts to test something in isolation will speed things up. We can better understand where a module begins and ends (i/o, side-effects.) Develop it rapidly in the harness and then a few (automated) integration tests at the end. It doesn't have to be a TDD-specific testing harness.
React Storybook is an example of a UI test harness. It's still manual testing, but we get that great separation-of-concerns goodness that makes for better designed (and easier to maintain) systems.
(1) install database (or point to dev,) configure app, run seed data.
(2) creating the state in the database manually.
(3) change lines of code for feature
(4) reloading app, navigating through to the feature state, manually verifying.
(5) fix runtime errors or bugs
(6) Repeat as needed. Commit.
We don't need to swing around the entire stack to craft some pixels or make sure some message is displayed under specific circumstances. How do we get developers to think beyond this workflow?I think TDD at the very least is a education/comprehension exercise in abstract thinking which will discourage scenarios like the one described above. Once someone is able to TDD and 'gets it' then sometimes the way they approach arranging code even without TDD is better. I think this is why we may have mixed messages like "TDD is great!.. but we don't practice it at work."
Using a test harness any sorts to test something in isolation will speed things up. We can better understand where a module begins and ends (i/o, side-effects.) Develop it rapidly in the harness and then a few (automated) integration tests at the end. It doesn't have to be a TDD-specific testing harness.
React Storybook is an example of a UI test harness. It's still manual testing, but we get that great separation-of-concerns goodness that makes for better designed (and easier to maintain) systems.
One important aspect of tests is to derive them from requirements. Not from the implementation. This is also true if your requirements are only implicit in your head.
TDD ensures this as there is no implementation yet when you write the tests.
It also implies the changing requirements comes with the overhead of changing the corresponding tests. This is what happened in the incident described in the article. In many cases development speed might be more important than test coverage.
Still worse are tests derived from the implementation (usually to boost done coverage metric) because they often break although the code fulfills the requirements.
Rule of thumb: Test only the requirements which are stable.
TDD ensures this as there is no implementation yet when you write the tests.
It also implies the changing requirements comes with the overhead of changing the corresponding tests. This is what happened in the incident described in the article. In many cases development speed might be more important than test coverage.
Still worse are tests derived from the implementation (usually to boost done coverage metric) because they often break although the code fulfills the requirements.
Rule of thumb: Test only the requirements which are stable.
I tend to think that the biggest flaw with TDD is that it assumes you have requirements, from which to derive test cases.
And In 7+ years of engineering at FAANG companies, I've never once had clear requirements before the software was complete (let alone started).
And In 7+ years of engineering at FAANG companies, I've never once had clear requirements before the software was complete (let alone started).
As stated tests are important, what varies is the style and ordering of writing them.
I don't like brittle tests that are specific to the implementation, such as assert that such-and-such isn't invoked--an equivalent function can be invoked and pass.
The order I do things:
I don't like brittle tests that are specific to the implementation, such as assert that such-and-such isn't invoked--an equivalent function can be invoked and pass.
The order I do things:
- think about the problem space, come up with some shape(s)
- list the test cases, but don't write the bodies
- code the happy path and runtime errors for others
- write the test bodies, make them pass
- clean-up any remaining placeholders
Sometimes (2) and (3) are flipped, more often interleavedA couple of things to mind when talking about TDD.
1. Tests can be unit-test, integration-test, e2e tests. Don't limit yourself.
2. TDD is a technique. Depending on the problem and your experience it might not be the right one to efficiently get you a working program and a good test suite.
Remember there is no free lunch.
3. Also, if you have never successfully applied TDD: Please stand stil for a moment. Some techniques require practice and TDD is one of those.
You need to invest time in order to use it efficiently. Once you do it, you will be faster and deliver higher quality code for a large set of programming tasks.
4. There are tasks where i don't use TDD. However, I usually go back to it as soon as I can. You can switch between the two techniques. There is not one way that is most correct.
5. Also, note: if you don't write tests first. Writing tests after the code is complete is more difficult. You might need to adapt your code to make it testable.
6. If you write tests afterwards, usually you will accidentally omit tests for crucial cases if you are not careful. I use line coverage and branch coverage tools to help me when I don't develop test driven.
1. Tests can be unit-test, integration-test, e2e tests. Don't limit yourself.
2. TDD is a technique. Depending on the problem and your experience it might not be the right one to efficiently get you a working program and a good test suite.
Remember there is no free lunch.
3. Also, if you have never successfully applied TDD: Please stand stil for a moment. Some techniques require practice and TDD is one of those.
You need to invest time in order to use it efficiently. Once you do it, you will be faster and deliver higher quality code for a large set of programming tasks.
4. There are tasks where i don't use TDD. However, I usually go back to it as soon as I can. You can switch between the two techniques. There is not one way that is most correct.
5. Also, note: if you don't write tests first. Writing tests after the code is complete is more difficult. You might need to adapt your code to make it testable.
6. If you write tests afterwards, usually you will accidentally omit tests for crucial cases if you are not careful. I use line coverage and branch coverage tools to help me when I don't develop test driven.
I don't think I have a good enough to brain write all but the simplest code without TDD. I specify what I want, write the tests, then figure out how to make it pass those tests. Thanks to libraries like @testing-library/react this approach applies as equally as well to when I'm writing babel AST parsers and custom languages as it does to developing a user interface.
TDD is so tragically misunderstood. I don't think this dude knows what he is talking about.
Case in point: you don't have to write your tests first. You can write a quick spike first to feel out you API, then rewrite that code with TDD.
Why is this dude so desperate to have this function written quickly? This whole episode could not have taken more than 20 minutes. Sloppiness is the enemy with software development.
"But in real life, features are way more complex than Function X should take a name and output a greeting with that name. Often times the product request will change mid-work, or you’ll realize that the feature can’t work as requested. Maybe your original understanding was flawed and you have to start over."
Smoking gun right here. This is just wrong and stinks of amateur. Features are almost always made of many small functions that do little bits of easily tested work. And if you factor you code well, which is a large benefit of TDD: having well factored code, changes should not collapse you whole sand castle. If that is happening, maybe go back to school. Oh wait, you never went to school, just a 4 week course so you can have low level programming job to toil at...
What he is missing here is the alternative: a big ball of mud with giant functions and poor tests to validate behavior.
Case in point: you don't have to write your tests first. You can write a quick spike first to feel out you API, then rewrite that code with TDD.
Why is this dude so desperate to have this function written quickly? This whole episode could not have taken more than 20 minutes. Sloppiness is the enemy with software development.
"But in real life, features are way more complex than Function X should take a name and output a greeting with that name. Often times the product request will change mid-work, or you’ll realize that the feature can’t work as requested. Maybe your original understanding was flawed and you have to start over."
Smoking gun right here. This is just wrong and stinks of amateur. Features are almost always made of many small functions that do little bits of easily tested work. And if you factor you code well, which is a large benefit of TDD: having well factored code, changes should not collapse you whole sand castle. If that is happening, maybe go back to school. Oh wait, you never went to school, just a 4 week course so you can have low level programming job to toil at...
What he is missing here is the alternative: a big ball of mud with giant functions and poor tests to validate behavior.