TW Hangouts | Is TDD dead? [Part II]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

The most interesting part to me was Kent saying that design is separate from TDD. I'm curious to see the reaction of all the people who say TDD leads to better design.

πŸ‘οΈŽ︎ 4 πŸ‘€οΈŽ︎ u/jshen πŸ“…οΈŽ︎ May 16 2014 πŸ—«︎ replies

All three of them have been way too agreeable. I really want Robert Martin to join one because he actually has some starkly contrasting views.

πŸ‘οΈŽ︎ 4 πŸ‘€οΈŽ︎ u/synt4x πŸ“…οΈŽ︎ May 16 2014 πŸ—«︎ replies
Captions
okay so it looks like we're live list if my indicators anything and this case welcome to the second of the conversations about is TD dead and with myself David and Kent so in the last part we we talked about our different experiences of TDD about how sometimes it gives us great flow sometimes not and differently for different people I mean can't find that flow more often than David does and we also talked about how um TDD and the notion of self testing regression Suites get conflated together and that they are actually different things TDD being one way to get there but we finished the part by really looking at a different issue which is can at times TDD leads to actual damage to design and one of the things that TDD proponents like myself often say is that TDD can actually lead you to discover good designs but david has seen things in the rails world that he feels are the opposite of that that of damage so really we want to look at see if we can get around to three questions during this half-hour segments one is is TDD the cause of this damage that david observes secondly is it actually damage is it a bad thing or a good thing because there's clearly disagreement about that and then thirdly the perhaps the meta question of how can we tell whether something is damaged or not how do we judge that so thanks David is the one observed the damage maybe you could describe a little bit of what is this you see is damage maybe that's a good place to start absolutely we send out in the show notes I think there's a gist um so let me actually see if I can pull that up because I think I can do too oh just one second yep okay you guys see that yeah so that's the that's the gist you can go to it in your browser if you want to have a look at it and it basically just shows one example of one kind of architecture that I've seen people arrive at either directly in this form or a version of this form by going through TDD with markets classes if we want to call it that where the idea is that at every layer of the of the application you can separate it completely from any of the other real pieces so you can take a controller in an MVC setup and you can figure out a way to test what it does without actually having to talk to the real model and without having that real model talk to the real database and without even having the controller run through its normal loop of dealing with with the request and the response we can mock all that stuff out and it's done through sort of a couple of patterns at the very top you see if there's the standard rails controller this is all extracted from a talk by a Jimmy Wyrick called decoupling from rails where he he just presented these ideas as as a path to go down and he then looks at how you first of all extract the meat of the controller out the business logic into this create runner you extract the model itself out into two pieces first of repository of how to get in Safety's models and then also a business model as he calls it that wraps the sort of the data axis of the active record it's not really I've seen some criticism about well this is just a hello world example of course it's going to look far more complicated when you wrap it in a hexagon pattern and that's true that's not really what matters what matters to me and when I look at test induce design damage and what I sort of service that damage is the creation of unnecessary indirection additional layers of complexity that we inject into the application for the purpose of testing it easier and when I say testing it easier a generally mean to unit test it without collaboration from from other parts of the application we can separate everything else out and say I just want to test this tiny little piece as a unit test it can't be slow it can't talk to the database it can't go through the request response cycle it can't do any of those things and this is actually this is a reasonable extension of that to its logical end I'm taking every single piece of an MVC application and slicing it enough times until every single slice can be unit tested in that traditional no collaboration form of unit testing and I've seen a variety of I've seen few applications that's gone the whole way where they've used both the command pattern to extract the action itself the repository and the business wrapper sort of this shows all of them at once I've seen many others take just one or two of them oh well we're just going to inject command pattern it into every controller such that we can tested in isolation and and each for me each slice whether it's the command pattern whether it's the repository whether the domain logic wrapper around a data access object for me all these slicing are damaged like I see an application that's worse by the end of this application of the patterns and I see that we're getting there through TDD and again as we talked about last time TDD there's a lot of different directions and the direction I'm seeing here is the Marcus TVD somebody wants to mock out sort of all these collaborators when they're testing just do one thing and last time I felt we were actually like we were all in agreement with oh well you shouldn't do three three-level deeps of mocking my position is actually starker than that I don't want to do even one degree of marking internally in my application I'm fine with mocking externals if you're talking to a payment gateway of course that payment gateway should be marked out if I'm trying to test the controller I don't want to mock out my model if I'm trying to test my model I don't want to mock out my database these are actually first level layer of mocking and in my opinion that drive that drive towards just getting the first level layer of mocking it creates this sort of flow to go down this path of getting all these pattern interjected and then the ultimate conclusion is this comparison is that you have all these layers of additional interaction because you need one layer in between each of the other layers such that you can mock from there and I have a hard time looking at something like this and looking at the more complicated cases not saying this is test induced damage the the application is worse off for what you try to do to make it easy to unit test it would mocks so the thing I found interesting about this conversation the reason I'm excited to have the conversation is is because I'm learning so much in the process of talking to you interacting with other people in between the sessions and this idea of test induced damage was something that was a surprise to me it wasn't something that I'd ever conceived of before so I wanted to really understand it now David you know a lot more about driving cars than I do but here in Oregon if if you get out of the car and you're someplace that you don't want to be getting a new car isn't going to fix that and I feel the same way about ascribing to TDD the the the the design decisions that you make you're making design decisions you're going to get feedback in some way and and to say that it's TDD that causes it seems like a conflation of of cause and effect you happen to be around TDD happen to be around you could design exactly the the same code that you showed without any tests at all or you could design it writing tests afterwards or a cleanroom or anything else to me the issue is more about all of the tricks that the gist displays are good tricks under certain circumstances and so for me it's it's not a question of TDD or not TDD it's a question of getting an understanding of of when each of those design moves is a worth the cost and when it isn't and and if somebody goes around and and just wants to to apply all of the design ideas every time to everything regardless of the context you're going to be in deep yogurt whether you write tests or not I think that's all fair what I will say is I don't think it's I think once you jump on the TDD horse or car or whatever you want to call it it's going to sort of want to leave your certain way as we talked about last time the good feelings of TDD when you feel like you're in that flow and you and you can ride just a little bit of code and then you can write some some tests for it I think it's most conducive to the cases when you are unit testing in that traditional sense of no collaborators and so forth when you move that level of testing up to say there the controller level or the application level it's no longer telling you that much about your design anymore because it's moving further and further away from the white box of working with a single object to the black box of working with an entire system and I can completely see how you get from A to B I can see that if if you like that TDD flow if you like that feedback post actually if you like it fast you're going to want that feeling as much of the time as you can and I could completely then it's not hard mental jump for me to say then if if you enjoy that why wouldn't you try to apply it everywhere why wouldn't you try to apply it to all pieces of code you want to write well I think that you do want to do that and people are trying to do that and then they end up in a place where if they knew that we're going to end up there when they started perhaps they wouldn't have but they didn't so they didn't end up there and they end up with a monstrosity that it didn't start out with an intention of creating this monstrosity when having all this indirection and having all these layers but it got there one test at a time so 10 I work to make faster at the time so I would say got there one design decision at a time TDD puts a certain kind of evolutionary pressure on on a design no no question about that and and testability as a principle puts a kind of a pressure on your design I think there's a reasonable question about grain size and and part of what I'm trying to understand in these conversations is it seems like there are a lot of binary positions along the analog dimensions and so grain size is one of those some people seem to want to go to one end or the other in terms of granularity of how much what's the Delta coverage per test so some people don't mind covering a whole bunch of of implementation decisions with a single test that aren't covered by any other tests and other people want to nibble nibble like a mouse and and just cover one decision at a time per test well there's a continuum and different decisions have different profiles of how often you're going to screw them up and so the neither extreme position makes sense I think being aware of the dimension and being able to adapt your style to to the actual cost benefit structures facing you at a given time that's that's my goal for myself and my students is opening up that kind of awareness and if you wanted to say hey don't take the extreme positions I'm I'm fine with that but to say that the kind of evolutionary pressure that TDD it's because you're using your designs very frequently from the outside to say that that that somehow automatically leads you to to a poor design like I don't like that doesn't I still don't have that connection in my mind in particular you say monstrosity can you tell me a kind of thing that you want to do to that Geist that the structure of it makes hard because like if it's just sitting there who cares it's it's when I want to change it that the design actually matters to me at least there's a direct correlation between the size of the code base and the east with which you can change it the larger something is the harder I found it to change it and especially when you look at something that has multiple layers of indirection that have to be kept in sync somewhat through the time so if you look at the repository tube is object 2 to actual active record object sort of that chain all the way down the repository needs to be updated every single time you you have a new interaction with your with your model because that's the layer you're going through so you have to keep that layer in sync somewhat between both what the caller wants and what the collie is able to to give so just that Tollbooth that and that tol you have to pay then every single time you make an update there that's an example for me of making things harder and making things more costly to change and more costly to understand to because I think that that's at least when I look at a system and I want to change it the first thing I have to do is I have to understand I have to have a clarity of what is this even trying to do if I can look at something that fits within ten lines of code well I mean you can write some very complicated programs in ten lines of code Perl golf notwithstanding and such but if that's not your intention if you're actually writing clear code and exact clear coat fits in ten lines to me that's endlessly easier to understand than sixty lines that has three additional layers of indirection that I have to comprehend first so that makes it so much hard for me first to get that realization of what is the clarity what is the system trying to do before I can even begin to propose a change to it so as a general position my position is that more code to do same things bad unless it's part of the sort of inherent complexity of the domain right but it's not in this case right even though this is an exaggerated lower case the two pieces of code are doing the same they're trying to accomplish the same business and go right so when you compare to that level then more code equals bad code it's a gross oversimplification but I think it's it illuminates why to me the cost of every layer of indirection the cost of every sort of additional wrapper I see is a very high price to play both in terms of understanding and maintenance and an evolution and all these things and I see that TDD is putting these pressures when you're trying to apply TDD as much as you can which I fully understand you're not right you're very happy to say well well TVD doesn't fit in this case I'm just going to bail I'm not going to TDD this stuff when I sees a lot of other people sort of they get addicted to it TDD is addicting it's a red green refactor is an addictive flow right I am I am the I am the poorest drug dealer on the planet I think you're very crafty of that and I think that the red green refactor flow is ingenious in that sense because it does give a lot of good feelings it releases a lot of dopamine for a lot of programmers as we talked about last time that confidence level when you get into that flow of oh well I have really great confidence in this I want to try to use this everywhere else that's where I see it goes off the rails I'm going to disagree completely with that I don't think this this effect has anything to do with TDD per se because I can imagine myself in this kind of situation using TDD and not going anywhere near the direction of the kind of layers that you're talking about I think on the other hand it's not entirely independent of the car that you're driving that's getting into this place because I think there is a testing a desire to make something testable as part of the driver but what's really happening here is this desire to isolate the various pieces to the degree that it's going it's the isolation I think that's driving you to this spot where and leaving aside the question of whether this is a good spot or a bad spot I think it's the isolation that's the driver when people are saying we want to construct these indirection layers they're saying well we want to isolate ourselves from the database somehow we talk to the database um how we in fact interact with the rest of rails I mean very very explicitly in a couple of places where I've talked Ivor with this approach to hexagonal architecture or other times that people have talked about it that said we want to get less dependent on rails we want to be and in fact that's the essence of their this hexagonal idea is you want somehow your application to be independent of the environment and the world around it and so I think it's this desire for isolation that's drawing people down this path and testability is kind of part of that because anything that's more isolated can be tested more easily supposedly I'm not entirely by bad either but I think it's the isolation that's the driver I will completely agree with that point but I think people are getting to that they're seeing isolation as a goal because of TDD because of unit testing that something that's isolated is easier to unit test and the reason I say that is when I watch people talk about ejaculatory textures and similar approaches to creating further isolation the only justification that makes sense in my book is actually the testing justification because all the other testing or all the other justifications I've heard have been so ludicrous as to be laughable especially when it comes to the hexagonal approach the number one I'm seeing that people pull out is oh I could turn this application into a terminal application yes I could use this from the command line like is that ever going to happen like maybe it will happen maybe you're working on the safer uh I don't know flight booking system and and in that particular very narrow case that is exactly what you want but to trounce that up as a as a general example oh look at this this is why I'm doing it one other example the repository oh look I could swap out my pack in such that I'm no longer talking to a database I'm instead talking to to an in-memory store or maybe I'm talking to a web service which is to me the worst part of design elation thing when you're isolating a piece as though you could swap in any other piece and the system would carry on as though it never knew whether it was talking to an a web service back-end or an in memory store they have completely different characteristics and all sorts of degrees right like performance and so forth you do things with an in-memory store that you would never do over a web service so to think that you can actually isolate yourself away from this stuff is to me just a complete pipe dream and the reason why I think people are willing to put up with this pipe dream is because that that's not the real goal that's not the the real bone they're getting out of it the real bone they're getting out of it is isolation for testability and testability in terms of mocking fast units has all these other things right so I just I don't buy for the general case the other justifications that people have put forward for for isolation especially when it comes to the hexagon approach in terminal apps and in memory versus web services and all the other nonsense the people are drowning out so certainly yeah I like your example of the difference between a web service and and an in-memory database because the the reliability differences between the two that's the kind of stuff I deal with all the time it has a profound effect you might think you're decoupled but you're really really not because in one case you have to deal with a bunch of failures that just aren't going to happen otherwise and and if you start with one and move to the other you're not going to have the right design for that so so the the boundaries between elements are aren't hard they're going to leak into each other to some degree and the question is how much are we willing to spend to get how much a decoupling between elements and to me that's the that's what I'm trying to understand myself as a designer is to see all these things as trade-offs and there's the okay so yeah I can work this much harder and I can get that much more decoupling and so your your example of the ten lines instead of the sixty lines I would see that as a as a cohesion argument to say wow if I'm solving one problem and and all the lines of code for solving it are all together that's highly cohesive which means it's going to tend to be loosely coupled until such time in the futures you realize oh no no in fact these five lines actually there's another way of implementing them and then you're going to have to break the ten lines up and and and create more elements for yourself I think one thing that's interesting there is is the relationship between cohesion and coupling because I think they're actually often in opposition like they're presented as though they're this pair that just wonderfully goes together always I don't think that that's the case I think oftentimes to get really low coupling you you do damage collegiate and I think that that's exactly what we're talking about here that the drive to get this level of isolation which is low coupling right is causing the cohesion to take hit and I think that there are often cases where I'm actually willing to trade high cobbling to get high cohesion I'm willing to say this piece of code is like my controller in an MVC application my controller will explicitly refer to the model it will explicitly refer to someone the authentication code it'll explicitly refer to to a mail or object and knows how to send out email all these things are explicit dependencies that aren't they can't be easily stopped out there they can't be easily swapped out I'm hard coding the class names right in there so I'm damaging the the coupling I'm willing to suffer hi coupling because I also get hi creation out of it I get a piece of code that does something in a very succinct space right and I'm a with that trade-off comes that I'm willing to say do you know what that piece of code is not going to be easily unit testable in that fast test no collaborators kind of way it's even going to be a little bit of trick to to mock it out so do you know what I'm not even going to try like I think that the payoff in that case is that I have that high cohesion I have a system that's easy to comprehend a clear system anybody can jump into and and see what's going on and I paid the price and I think that that's why this discussion to me is interesting I think it's why at least just naming and calling out and introducing as a concept test induced damage that testing that just drive the testing at times has towards isolation toward its low coupling can be harmful to other aspects of the trade-off that's not to me that that shouldn't be as controversial as it's been received at least I think there's a there's another option which is that that so the the email example I think is a great one you always have the option of reifying intermediate results sometimes it's worth the price and sometimes it isn't mocking isn't the only way that you can eliminate external dependencies you can also and I use the example of a compiler which goes a lot deeper I mean you have the the parse tree is in there me result you have a single assignment form as an intermediate result you have the assembly code as in some symbolic form of the assembly code as an intermediate result in all those cases the trade-off has really been clear for decades that that those intermediate results objective are fiying reifying having those intermediate results as things gives you a lot of leverage and in the email case I think you there's a missing one of the options is there's a missing piece of design which is thinking about how intermediate results as things might make code testable without needing to use mocks it's one of the options it needs to be in your bag of tricks it's it's subject to a set of trade-offs like everything else but that that's the one that like when I have something that's just really hard to test and I take a walk and I chop some wood and I feed some goats and I oh I see the insights that I get in that moment generally our design insights so difficulty testing is a symptom of a poor design once I have the design inside oh I thought these two things went together and really they go apart or vice versa I thought these things were really separate and if I put them together a bunch of things suddenly become easy once I have that insight then I give both and that's that's what I'm shooting for I want testable designs that are easy to comprehend that are easy to use in different contexts that are easy to modify and to me the gating factor isn't isn't my coding workflow it's really about how much design insight can i get going in my own head I think that that's of course the ideal so the idea is that the the testing drives you towards a better design and I've seen that I've had that happen I've had it happen to me that I either through TDD would test first or test afterwards that the tests told me something about my system that made it better but I've also had the opposite happen like that's I don't want an equation between oh this is easily testable thus it's better I think that that's the fallacy that a lot of cool decisions are currently being driven off that it's not a trade-off it's being presented simply as a matter of if you think about it longer if you go up with more goats for longer periods of time the inside will arrive and you will have this disap if aney that's going to improve the design and make it testicle I often will propose that the solution is not there you cannot both have the easily testable and the good coherent design not always but there is a variety of cases of this where I think this whole did we looked at in the gist is a perfect example of that trying to think harder about how the controller could be better structured in such a way that that it was easier to test um I think we're just not getting there and I just I want to stop people from at least thinking that it's the only thing holding them back is that they haven't thought about it long enough I think sometimes the answer is there's not an answer you're not going to produce better code by making more testable I'm gonna say something to you David then I think you probably don't hear very often and I I think you don't have enough self-confidence I think that the design that there are design insights out there that maybe you can't see them today but the that unlock that win-win situation now you absolutely have to make progress in the meantime if you don't know a good way to design it so you have to get the next test running or release the next feature however you want to talk about it even though that you know that the design isn't quite right you know just smells bad but I'm I'm gonna be optimistic I'm going to take the the optimistic stance as we get close to time today to say I think that really that there is a good design out there there's there's some abstraction that we're missing and and if only we could figure it out then we could have our cake and eat it too in the meantime we need to choose I think you've crystallized what I call faith based TDD this believed that TDD will eventually even though we cannot see it and we have no evidence for today will lead you to the right design and I think it I think that that's actually that was the loop that I was in for a while and that loop just melt led me to feel bad about myself when I couldn't arrive at these conclusions like the faith in TDD was driving me towards the sort of it must be out there I'm simply just not smart enough or have not thought about it long enough um there's not there was not an out and I think that that should realization have come too and that's why to me TVD as a faith based programming principle is dead that I cannot anymore just place my faith the TDD eventually is going to lead me to this proper design I I will accept that they're just it for a large number of cases it's just simply no way the TDD is going to drive me to the better design that actually TDD is going to take it to the wrong place now we're standing that there are other cases where it will take me to the right place but I'm giving up on the on the on the faith in it as a sort of a universal solution that it is going to event indeed right there yeah I wasn't referring to TDD or not to TDD I was talking about software design in general for first and second TDD isn't taking you anywhere you're making the decisions you get where you get if you say well these aren't the design decisions I wanted to make we'll make different design decisions in you stepping back to the principles how are you going to get feedback about the the physical behavior of the system you're building how are you going to get feedback about the API decisions that you're making how are you going to feel good how are you going to earn that confidence I talked about last time you know you know nobody's going to hand that to you you're going to have to earn it how are you going to earn that that to me is that the essence of the question and I think that thinking about software design - I don't care about TDD not TDD thinking about software design when I can finally have that insight that's the moment that pays off both in terms of dopamine and in terms of externally measurable results that's the moment that that I'm really seeking because it just pays off so big and that you know I don't think that's tied to workflow at all I think that's that's about knowing when to work hard and knowing when to rest and pulling lots of influences in from from other places and knowing how to collaborate with other people so that you're not limited to the the genius in your own head full workflow is way way down on the list about whether or not you get to that moment that really pays off big for software development Martin are you going to stop us I've been thinking when to join in and be Timecop I'm trying to think of some dramatic thing to move on to the next conversation but actually I can't think of a dramatic thing to move a fixed conversation have you two got any ideas well I'd really like to explore the this what are the trade-offs involved I think that's that's a space that we really haven't talked about what are the what's the context that effects things like how you seek out how frequently and how do you seek out feedback and I'd love to talk about that I think there's a ton of juice in there things that I haven't really thought about and I'm in this for my learning so I think that's where the granularity debate can sort of come in and where we're test first versus test after and and the value for example of test first at a higher level of granularity I'm very unclear on that okay so that will be the theme that we'll move on to next time then and King Kent can kick us off and head in that direction but now our time is somewhat passed so it's time to be quiet for a bit and let the internet to see what it comes up with over the next week and as for the next time we'll post it it may be next week but we haven't actually planned it out yet we've mapped all to plan it out before the video but oh well such is life well we will post it on our feeds keep an eye out for it back ok
Info
Channel: Thoughtworks
Views: 65,544
Rating: 4.9432988 out of 5
Keywords: #hangoutsonair, Hangouts On Air, #hoa
Id: JoTB2mcjU7w
Channel Id: undefined
Length: 35min 20sec (2120 seconds)
Published: Fri May 16 2014
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.