Test-driven development: A great idea hiding behind a terrible implementation?
itnext.io
itnext.io
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).
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.
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.
(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).
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.
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’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.
That's not what you describe.
Companies that sell themselves on TDD (among other things) are part of our dataset. Maybe “automated tests” isn’t the exact literal description of that, but I didn’t mean it as such.
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...").
Also @moksly's point seems at odds with an apparently highly regarded piece of software, SQLite.
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
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.
No. The only thing that consistently affects speed is size of the suppliers, the bigger the slower.
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 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.
Personally I need tests to run in a few seconds. I work on a large project that does it so it's definitely possible.
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.
So the type of customer you are attracts those type of devs.
Edit: this doesn't seem downvote worthy....
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?
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.
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.
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.
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...
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.
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
Regurgitating others' opinions and making multiple unfounded assertive statements is key to demonstrating he has already mastered the software domain.
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.
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?
If it doesn't in fact do that for this person it's totally valid to mention that.
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?
Maybe not, but you're welcome to publish an essay on what you think.
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.
bjornsing's comment is implicitly highly critical of them doing so.
Something like "I dont like TDD" or "I struggle with TDD; here are my thoughts" would at least ground us in our expectations.
What does this even mean? Their experiences are valid?
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.
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.
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...
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.
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.
I like this. I mean, as a description, not so much as a fact, but it is what it is :D
Testing nature is much easier, and thus establishing norms in these subjects is easier.
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.
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.
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.
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.
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.
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.
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 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.
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.
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.
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.
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 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.
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.
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.
(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.
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.
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.
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.
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 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.
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 interleavedI'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.
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.
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”.
Pointless unit testing is a separate thing.
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.
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.
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 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.
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.
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.
Your previous-to-last sentence applies equally to a software project with or without tests.
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.
Alternatively incognito or no js should do the job also.
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.
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
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.
The rush to produce code, now, is making working in this industry suck.
Who wants to think, when you can code, right?
Of course, I don't always do the stopping and thinking part...
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?
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?
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.
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.
IMHO only thing dumb is developing without testing
25 minutes, 16 points - all that it takes?
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.
Don't seem fair to call out author on not writing tests because they never said that.
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 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.
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.
There are so many attributes.
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...
... 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.
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.