 My name is Daniel Brulund. I come from Sweden. I'm really happy to be here in India. We're pleased with the food and meeting all of you funny and lovely people. I'm really enjoying my stay here, so Thank you very much for that. So that was the kind of nice start of this talk. Now we're gonna get to a bit more nasty part. And I would like you all to pair up with someone close to you. I'm gonna tell you a little bit later on about our horror story that led us to this discovery. But I would like you to pair up and tell the other person a little bit about some code horror story that you've been in. Probably some legacy code mess thing that you've been experiencing. So pair up and take a few minutes to just tell the other guy about your worst experience, okay? Right? Please go ahead. Did you, did you get a feel for pain? Do you feel anything? Pain? No pain anymore. No pain anymore? Okay. Yeah, that's good. Ignorance is a... No, sorry. So I hope you all got in the mood. Now we're gonna try, now I'm gonna try to talk about change horror story. So we were about to, me and my colleague Ula, we were about to change codebase once. So we wanted to make a change to our system. So we did that change. We just implemented it naively. Okay? But what happened was that we got a few, you know, compilers, code rash, so on. So we thought that let's just fix those errors and we'll probably be done tomorrow or so. So we started patching those errors. But we got more errors, huh? See that before? Yeah. So I'm fine. Patching, just met the more errors. And when we tried to patch those errors, we got even more errors. And eventually we thought that, okay, but if we just do these things we'll be done and we can check things in and everything is fine. But when we had like, when we had like 200 errors that we were just getting to and we were finished with those errors and we just pressed save and then, you know, we got a whole bunch more because the compiler could move one step ahead in compilation from the first one. And then we thought that this is not working. It was like trying to stop an atomic blast shockwave with our hands in the code. It was like, we just couldn't do it. So one morning we had said to the team that this is, just give us a few days and we'll fix this. And after two weeks of trying to stop people from checking in certain parts of the code that we were editing and just generally had mergers who hadn't been able to run the tests we had in two weeks and just a mess that we had to admit to the rest of the guys in the team. Sorry, guys. This is not leading anywhere. So we just had to revert everything, all of it. So that was kind of a defining moment, I think, in our careers. We realized that we could throw things away, actually. But, you know, we really needed to do that change. So we're thinking a little bit and we did the same change. And, of course, we got the same errors, right? So one definition of madness is trying the same thing twice, you know, and existing different results. So this might seem a bit stupid, but we figured that if we just note a prerequisite for this change that we had, so that if we did this change, but we had done this one before, then these errors wouldn't occur, right? So if we just would have that done before, we wouldn't have those problems. So we went on and we did write down a prerequisite for each of these groups of errors because there's usually groups of errors referencing the same kind of problem, right? Can you give an example of three prerequisites used in this context? Let's say that a class is in the wrong package because you're changing, you want to maybe break out the part of the code that is used in several places. But when you do that, you have, like, different kind of dependencies. So you need to break out maybe a circular dependency that's within a package or within the same project is not a problem, but when you break it apart, it doesn't comply. So that's one kind of prerequisite for this. So, and after this, okay, we reverted again. So we threw away the things that we did, the code that we had written to get the errors, but we kept the notes of what we had done, okay? And then we tried for each of these prerequisites to implement them. So we formulated, I mean, something that we would do in the code. So now this was our goal, this one. So we tried to implement that part naively once again. And we got some new errors, right, because this was a messy system, okay? But we did the same thing there. We just noted the prerequisites for those errors, okay? And then we reverted. So we went on like this, picking the next leaf and so on, because these are, if you see this as a graph, these are leaves and graphs, right? So we went on picking leaves to do here. And eventually we could do one of these prerequisites without getting any errors, okay? So we did that, and if this change made sense to us, we could check it into the version system, commit it, okay? And we went on with the leaves. And when we had done the leaves for one prerequisite, we could do that one, right? No problem, because we had fixed everything that we needed to do before we could do that, okay? So we just went on with all the leaves, working our way back into the original change. And after a while, we had done all the prerequisites for our original change. And at that time, it was actually pretty simple to do the thing that we wanted to do. But we had to set up the system for that change to be possible. And at this time, we were done with that part. But then there was a lot of mess, but let's not talk about that right now, okay? We went on with this kind of approach, fixing more things in the system. But this part was done. And we did it by just trying to find the prerequisites of the thing that we wanted to do, so that the thing we wanted to do was really easy and we would get all that in place. Right. So if we tried to find some things, some rules about this, that would be right down the goal. We did right down the goal, because doing so, it got much clearer what we wanted to do. And it was much easier to stay focused on the thing that we wanted to achieve. I mean, in a legacy code base, there's so many things that you want to fix, right? Some parts of the code that you really, really, really hate, and you want to do something about it. But to avoid getting lost, you write down the goal all the time. Both for the original goal and for the prerequisites. The definition of legacy code will be good here. In my opinion, legacy code is a coval veteran code. My friend there, I don't think it's in the last six months, it is a legacy code. Yeah. Okay. I think my definition of legacy code is things that you check into the versioning system. So I think that's... Michael Cutler says any code that doesn't have good unit tests? Yeah, that's not a definition. So you could use any code that doesn't have unit tests could be legacy code. That's not a good definition, I think. So code you're afraid to touch could be another definition. So, yeah. But anyway, so you write down the goal. You try things in the system, naively. Be naive. Don't try to, like, figure out what every change is going to lead to. Just do the thing that you need to do, okay? And an extremely important thing that Venkat talked about yesterday. Revert both broken code, okay? That's extremely important. You feel like you throw away things, but you don't. Most of working with code is about learning. Not about, you know, slashing out code. So you learn things, and it's not the code you wrote. It's not everything that you did, okay? And the fourth one is fix the prerequisites recursively. Try to find the leaves in the graph. Work your way. First out, to build up the graph, and then you work your way in back to the original. Others, you just have patience and let them work in getting the prerequisites right. Most of the times, the leadership wants, I want this fix out to the pessimist in a month's time. Yeah. So you go on to that question, and we can talk about that a little bit later on, because that's a huge issue, I think. So we'll try to get to that if we have time. Otherwise, I'll be available after the session or grab me during the day, or so I'll be happy to talk about it. It's a big issue, I think. And I don't think it takes months to do just enough to get what you need. No, that's another thing. I've done this for big things, and working structurally, you can do things within days that you thought would take maybe weeks or months. So it's really helping you stay focused and just do the things that you need to do. Definitely. Thank you. Some of the benefits that we have seen by doing this, since you're doing the small changes, the leaves things, which is another thing that Venkat mentioned yesterday. Just do small things. These are usually simple things. You just move one method or you move one class. It doesn't have any, give you any problems. You just move it to another project or whatever. Since you're doing such small changes, you can always check your code in. It's always in a working state. And you can stay on the main branch, which I really recommend if you're going to do refactoring work. Don't branch out. You stay on one branch and everybody work in that branch. So you're always deliverable by doing so. You have a goal focus. You're really clear goal focus. You only do the things that you need to get your task done. You get a visual... I always have a problem with this word. You have a visualization of what you do. It's like a memo for yourself for the next day, for after lunch, after the weekend, after your vacation, or so on. And you can also cooperate on doing these things with somebody else on the team or the whole team together. So it's easier to pick someone's brain on this if they actually did this kind of graph. So it's really good for this. Called the Mikado method. Maybe I didn't mention that, but we call this the Mikado method. And the reason... Have you seen this game before? It's sometimes called pickup sticks. So you have some sticks like this and you put them on a table. How many have seen this kind of game before? How good? So you have the sticks and you put them on a table and then you just drop them. And usually they fall in a kind of heap of some kind. And if you pick one of the sticks, you're supposed to pick up the sticks and the more sticks you pick, the more points you score. But you're not allowed to... If another stick moves when you pick up the stick, the turn goes to the next guy. So it's easier to pick up the sticks that are on top of the pile than the ones that are below a lot of other sticks. Because if you do that, all the other sticks will fly and you have to pass the turn to the next guy. It's a little bit the same when you change code. Like we did, we just did the original change, trying to pull that out of... And we got a lot of errors, just like the sticks flying around. But if you pick the sticks from the top of the heap all the time, the other sticks don't move and eventually you will get to the bottom stick, which is often a higher scoring stick since you form the sticks in a particular way when you drop them. So it's kind of the same with this method. The difference is that the pile of sticks in software is huge. You have to just go for one of the sticks and say, this is our goal. We're going to get this stick and when we get that one, we're down with this one. And then you pick the sticks above it and then there's probably a heap below it as well. So that's the background of the name to remember how to go about with the change in code. Alright, so anybody want to see some code? So this was just a lot of background and kind of theory or process about how we do this. So let's try to do an example. Are you passing around the USB sticks? There are some USB sticks with code and the presentation and our book on this. So I recommend you get the code folder, the Eclipse version if you need it, and the PDFs that are on there in the root. So those are three things. Yes, let's do an example. Welcome to Pasta Incorporated, a software company that has a product called Master Crypt that's a really, really, really secret algorithm for doing kind of encryption stuff. Right? So remember this and I'll switch to the development environment. Just hold on a second. Thank you. Here we have the application. We have an acceptance test for it just to see that it's still working for the example. Often when you work with legacy code you don't have maybe that much test depending on which definition of legacy code you're using. When we first did this we actually had not an extensive acceptance test suite but we had some tests that could support us but we relied a lot on the compiler. We relied a lot on automated refactorings. So let's look a bit at the code. This is exactly the same code that's in the Java version of the example that you're going to do later. So we have the test here and as you can see we have some kind of UI here and the UI has a method called LeetMessage. So what it does, this is the secret algorithm that they have. So they replace all the lowercase ease with threes, right? So that's the algorithm. It's a really, really secure one as you all understand I guess. Okay, so let's look at the coder. Let's see LeetMessage. Let's go into that, see what that does. All right, so I can draw this here if you like. So we have the acceptance test and the acceptance test is using the UI, right? So we have a UI class here as well. Can you see this one? Enough of you can see this one. Oops, let's not tear down the interiors here. So we have the UI here and the LeetMessage that we use. So what it does is it takes the unencrypted, unleeded string and it calls application and tells application to Leet this message for us. Okay, so it sends in the string and it also sends an instance of itself, okay? And then it returns Leet and the Leet. But what happens here in the Leet method? Let's see here, we're passing ourselves to this one. So the UI uses application, okay? So we have application here, application. So the UI uses the application. But here we have the application. It's using the UI, right? Does it look like it? So the application is using the UI. I can spot some problems here. I will probably get to that later. Okay, so the application sets, it calls UI back, the thing that we passed into the class, the callback, so to speak. And it calls setLeet and it also calls Leet this string, all right? So we have a leader here and the application uses that one. Right, we can go into the leader as well to just look at it. And it just does the replace on the string, okay? So this is the code. It's like five lines of code, right? How big a mess can that be? Well, we'll soon find out, shall we? So now, back to the path they incorporated. One day sales come into the development hall and they say, you guys, we just sold this application to a new client. Isn't that great? And all the developers go, you did what? We sold it to a new client. That's great. And the developers go, but you told us we would never have another client than the one we have. So the client they have is called Gargantua Inc., okay? And the new client is called Stranger Eons. So they just couldn't understand how stupid could the sales be. So what we're going to try to do here is see if we can... So the goal here is to make a new deliverable for Stranger Eons, okay? Of the system, a new deliverable. So it's going to be a new application, basically, for them. But they cannot share any of the code between those two clients because that would really be a bad thing, okay? So how should we go about this? I suggest that we write down our goal, okay? So we want to have a new deliverable. If you can't read in the back, it's in the PDF. This is chapter two in the Mikado method book that you got in the PDF, among the PDFs. I hope you can remember what I'm saying while I'm writing this here. Otherwise, when you do the example, you can come here and have a look. But we want to have a new deliverable for Stranger Eons. Stranger Eons, like that. We usually draw two lines around the original goal because sometimes these graphs can grow and it's easier to find the original goal if you just put two lines around the original goal, okay? So what does that mean in this world? Well, it means we need to have a new project for Stranger Eons. So we do a little bit of analysis here just to get started. But this one requires us a new project for Stranger Eons, like this. And then we draw an arrow from this one to this one because this one depends on that one, all right? So we need a new project. And since we in this case already have an acceptance test, we want to write a new acceptance test for the new application as well, okay? So we do a little bit of TDD here. So we need to write acceptance test for, I guess write SE for Stranger Eons here, okay? And we can write that test before we have the new project for Stranger Eons, right? So I draw an arrow here as well. Okay, so now we got some stuff we would like to do here, okay? It shuts down. Yeah, it doesn't give me power for again. So let's see here what we're going to do. We're going to make a new project for Stranger Eons, right? I have a template project here that I just used to copy so I don't have to set up test folders and stuff like that. So I copy this and I create a Stranger Eons project, right? And we got the main stuff here. So I'll write the test here as well. So Stranger Eons acceptance test. Okay, I'll put it in the Stranger Eons package. Like that. Okay, so we're going to accept those tests here. So I'll just write a test for that. Test Stranger Eons leading. Naming things is not really what I'm good at. So I'll just assert equals. So we're going to have something pretty much like the other test we had. We want to have leaded and their algorithm, their very secret algorithm is that they replace all the capital S with fives. So this is the information that cannot be shared between the two clients, okay? So we're going to have the UI have the lead message method. So pass in secret like that. And then the result should be 5e correct like that. Okay, UI. So I'll just create a local variable UI and I'll change that to UI. And then new UI. So, okay, I get read here. This is interesting. Okay, so I need a UI here in the new project, right? But the UI is up here in the mastercript project. It's there, right? And I can't let the new project reference the old project because then I would have to deliver everything with the new project. And that means I would share this information between the two clients. I have kind of a constrain here. All right, so what do I do about this? I can't go on, right? So what I need to do here is I need to extract the UI code to a new project. Or I can make a lot of decisions here on how to go about. But I'll just naively think that, okay, I want to move the UI stuff to a separate project. Okay, so I want to put UI code in new project like that. Okay, and it was that one that was causing our problems, right? So we wanted to get this one done before we do this acceptance test, right? Okay, so in order to put the UI code in a new project, we need to create a new project, right? So we need to create UI project to do this. And we need to move the code, move UI code to new project. And in order to do that, we need to have the project created already, okay? So now we have a code rash, right? It doesn't compile. But we have some new stuff that we want to do. So what I do now is I will just delete this. You can revert in your versioning system if you have one. But I'll just do everything now in the IDE, okay? So I'll just delete this code that I just wrote. And I think, oh, should you really delete the code? Yes, I really want to delete the code, okay? I want to have a clean state when I go on. Right, so we're back where we started, right? Are we? Really? Yeah. We have information, right? We're not back where we started. We'll learn something about the system. So let's see here what we're going to do next, okay? Next thing we're going to do is going to run the acceptance test just to show you that it still works, okay? So everything still works the way it was supposed to do anyway. So the next leaf in this graph is to create a UI project. After that, we can move the UI code to this new project, right? So I'll just create a new project here, UI project. As I said, naming isn't my cup of tea. I hope spelling is so far, so good. So we got a UI project here, okay? So that one is done. Now we want to move the UI code to this new project. So let's just move this code to the new project. Oops, red. Code rash. Can you see that here? Okay, good. There's a lot of red. Part of that is because we haven't had the mastercript project reference the new UI project that we just created. So I'll just add that to the dependencies here, okay? Now we got a few less problems. But if we go into this, the UI code here in the UI project, we can see that the application is needed in the UI project, right? So we need, the UI needs the application. Okay, but the application also needs the UI. So this is a problem that we have to solve, right? So what do we do now? You think, I think we're going to try to resolve this circular dependency. Resolve, search, dependency. So in order to move the UI code to the new project, we need to resolve this circular dependency, okay? There's a lot of ways to do that. I prefer to just shoot in an interface somewhere within this code to just reverse the dependency arrows in that part of the code, okay? So what I would do here is I would extract an application interface to do this, all right? So I want to extract application interface here. But there's also this application here. It's being created in the project. So I also need to inject this dependency in the UI here, okay? Otherwise I would just create an interface without really breaking all the dependencies. So I have to inject app interface in UI, all right? And to resolve the circular dependency, I need to do both, but I cannot inject the application interface in the UI before I actually have the interface, right? All right. So what do you think we do now? But the code is red. Should we really extract it now? Should we do something first? Revert. Yes. Thank you. So we revert the code. And this time I'll do this manually. You would use a versioning system if you would work with this, okay? So I need to remove the dependency on the UI project and I will delete the UI project, right? So try the acceptance test and it's still working. Okay, good. So we're back where we started, right? No, that's the right answer. We know a lot of stuff about the system and how it is structured and what dependencies we have and what the things start up we need to do. So the next leaf in this graph, can you tell me which one it is? Extract application interface. Thank you. So let's do that one and see if we have any luck. You can almost figure it out by my disposition here of the paper, right? But we'll extract an interface and that's a refactoring in the IDE. I prefer to use that. You can do it manually as well. If you use something like Emacs or Vim or some of the other, application interface, as I said, naming isn't my thing, right? We want to extract the interface and put the elite method on the interface. There's not much to choose from here, right? In reality, you probably have to choose from a long list of methods, which one you should extract, okay? So I'll extract that one. I got a new class here, application interface, which is pretty simple, okay? Now I have to go to the UI. That one is done, right? We could check in here, right? This would be an opportunity to check in because we can run the acceptance test and see. If we would use a distributed versioning system, we would probably check in right now. So it still works, great. But we have like a kind of pending state here, so we would like to do this. We would like to finish this. So what we're going to do now is we're going to use injection. So we inject the application instance into the UI, okay? So if we do that by creating a default constructor and inject it there, so for that one, I want to change the method signature. So I want to add application interface. And here we have the opportunity to choose a default value that will put in every place where the default constructor is called. And I choose to create a new application. So we're basically pushing the instantiation of this application from inside this class to everywhere where the constructor is called by doing so. In this case, it's probably two places, I think, in the code, so it's not that many. But it could be like 100 or 500 places in your code. So this is a nice refactoring. So I do that. I get the application here. But I still need to replace it there, right? So what I do is I initiate this.application. I set to application like that. And then I can remove this instantiation up here. Okay. I'll save that. Everything compiles. I run the tests. And we hope that it works. I do. Oh, it worked. Great. So what did we do now? We extracted the application interface. We injected the interface. So we resolved the circular dependency. Okay? Because the UI is only using the application interface. And the application is using the application interface. So we reversed the... We broke the dependency circle. So since it's compiling, tests are working. This is something that makes sense. We could check this in. And we can check it off here in our graph. Okay? We're done with those ones. Right. So this is good. We're actually getting somewhere now, right? It's not like we're just trying things and have to throw everything away. So the next step here, we want to create the UI project, right? The next leaf. Because we've done these things. So this is not a problem anymore. So now the next one is this one. Okay? So we want to create the UI project. And after that, we want to move the UI code to the new project. So this time we'll add the UI project beforehand. Because it's nice to move code without potentially getting any errors if we're lucky, right? So now we get that dependency. And now the application interface is actually a part of the UI code. Okay? So we're going to move both of those to the new project. And ta-da. No errors, right? Amazing. Let's try and run the test. See if that works. Amazing. The test works. It makes sense, right? We have broken out the UI code to the new project. We created the project. We moved the UI code. So we put the UI code in the new project. So I call this kind of decision node. This one is also decision node. We choose which way we want to go, but we're not detailing how we're going to do it. We do that later. We want a leaded secret, but it got leaded now. If you can read that, I'm not sure if you can read it in the back. But it says leaded secret, this is expected, and we got leaded now. But that's not that strange because we didn't actually implement the Stringer-Eons application here. So we'll just do that by... In the other code we had a leader, but in this code we'll just simplify things a little bit and we'll just do that right here. Because sometimes when you're doing this kind of refactoring, you realize that the code you have is really much more complicated than it needs to be. So in this case we do a little simplification here. So we replace all the capital S with a file. Let's save this and let's run this last test. It worked. Thank you. Question? I wonder since you put that into the unit test drive... I could probably have done that. I've been in applications where it's such a mess that it's hard to unit test and it's even hard to acceptance test it. So we would just have had to go on even without doing these things because the changes that we needed to do were so... they were, you know, touching so much of the code. But we did that with automated refactoring support so that kind of helped us feeling secure about what we did. In this case I have a test for it that is just to prove that the application still works. But I've done this without having tests and without writing tests on a large scale just because we had to do changes to the code before we even could do unit testing. So definitely... Yeah, definitely. Because when we broke this dependency it would be much easier to actually do that kind of thing. You're definitely right. You should do unit testing of your code. Sometimes the scale you need to change things on makes it hard to do that within the time frame that you might have. But if you have the chance where it's applicable, do unit testing. Definitely. So this was the example. Right? More complicated than five lines of code. Yes. No, we're sorry. We have. It was... I find it successful. Some people say that, okay, so you get this much for five lines of code. How much is it for a thousand or a ten thousand or a hundred thousand or a million lines of code? It doesn't really grow with the scale of the code. It might grow with some kind of logarithmic of the code but not with the scale. So usually when we do this kind of extracting interface, in this case I changed one or two places. We could get like five hundred or a thousand source code files changed by just one of these changes. Okay, so it's on a larger scale. All right. Time flies when you're having fun. Now I hope that you're ready to try and do this. So how many people here have laptops with some kind of development environment on? Oh yeah, I passed around the eclipse. So how many people doesn't have a laptop? All right. So if you guys with a laptop could pair up or tree you up or quart it up with guys that have laptops. Okay. So I want you to try and do this by yourself drawing this kind of graph or this graph so you just get a feel of the mechanics and get the feel of getting the feedback from the errors that you have, okay? So I'll just... I can show you a little bit about... this is the stick that you had. On there is a... in the example folder, in the code folder there's a cut at Java and this is the code I used and you have to... there's setup for eclipse so if you import those two projects into eclipse you will hopefully have the same setup that I did in my example, okay? If you don't know how to do it raise your hand and I can help you or I hope that maybe some of your friends can help you if there's a lot of problems. All right. So that said, I'm gonna show you a page where you can get the code if you don't have it and get some instructions some easy instructions about it, okay? But please go on and don't just start if you know what you wanna do just please get started. In chapter two in the book this example is described, okay? So if you wanna see exactly the steps you can go into the book Mikado method book on the stick and just follow that example, okay? Please go ahead. All this code is available at github under Mikado method so if you wanna use github you can do it if you have a wifi there are some instructions about the code and everything up here but hopefully you'll define anyway, okay? Raise your hand if you have a problem or a question or anything and I'll try to walk around with you and see how it's going. So we try to give our view on refactoring especially when you do bigger factorings it's not a lot of the details, you know extract method, that kind of thing but just how to think when you're going about doing your factorings at large. So this is the book, this is me and this is Ola, the other guy writing the code. There are some URLs here for the book and for this Mikado method. You have our Twitter IDs here so if you wanna ping us or ask anything just do that. All right, so that said do you have any questions or statements or anything you wanna say about this exercise?