 The session is Who to AHA? Refactoring Story by Gopal S. Akshantila. Gopal, we are glad you are joining us today. So without any further delay, over to you Gopal. Hey guys, thanks for attending this talk on Who to AHA? Refactoring Story. So I'm Gopal S. Akshantila. I'm a software engineer at Salesforce. My Twitter handle and website. Feel free to reach me out, reach out to me if you have any doubts after this talk. And let's get into the talk. What's refactoring? Most of us think refactoring is like maybe putting code from one class to another using ID shortcuts. But let's ask the person who wrote an entire book about it. As for him, refactoring is like altering the internal structure without changing external behavior. That's like, that brings me to the goal of this talk, which is, as a dev, I need to refactor to make my code best refactorable. That's a discussion out there. But that's like just saying, I want to build my code pieces like the Lego pieces. Why Lego pieces? Because they're the ones which can be replaced, reused and most importantly, they can be composed together to build different structures. So as long as your component is isolated, like Lego piece, my point is, you can sort of refactoring change without affecting the external components which are dependent on it. But let's see what sort of, what sort of, how can we actually see, see this in action? Because first of all, how do you pitch this story for funding? You know, building features. And of course, managers are not very interested to fund you for refactoring. There's always something to refactor. But that said, there's always, there's a small trick that you need to follow that's like speak in their own language. And this worked for me. Like I came to a man, I went to my manager saying that I have these three things like methods, obstacles, metrics, what sort of methods I'm going to focus on and obstacles that my code base has for extensibility, readability, etc. What metrics will I use to prove my point that I have refactoring, we have achieved something better. So the methods that we're going to focus today are just two of them, but I promise these two are going to change the face of your code. So it's like human readability first of course, as you know, code is for humans and of course, machines doesn't need refactoring, they can do an initiative code and then component isolation as we have seen you want to build components like Lego pieces and obstacles are again, we're going to focus on two simple very common obstacles, but then we can see how just removing these obstacles can help code base a lot. First one exceptions, of course, and which are omnipresent in all the of course all the languages today I'm going to focus on Java, of course, Java is the simplest language that you can actually do functional programming on and one of the common and very, very famous language that's the reason I chose Java, and we're going to talk about exceptions and mutability which is even more predominant in Java world JVM world of course we have some modern languages solving the problem but we're going to discuss on how they're solving and why we should also adhere to it even if the language doesn't give it out of the box. And some of the metrics like cognitive complexity which is inversely proportional to the readability and testability of course which mirrors how isolated your components that we're going to see how that can help us understand how good is our code base. So this is the big picture hope you understood what you're going to do and we I'm going to show you a lot of code on the slides and but don't worry, I'm not a big fan of course showing hold on slides, but I'll be sharing you the slide deck and then I'll be sharing you a repository in the end where you can go back and refer. And I'll be also sharing your blog post where all of this is written in detail so you can read at your own pace. But that's it today my intention is to seed you with ideas so you can go back and expand and connect those dots and sort of get the big picture and this 1520 minutes we're just going to focus on the high level stuff so requested to not focus on the details that you're going to talk to and just grace through it. So let's start with obstacles, obstacle one exceptions exceptions are the most abused language feature in my book because you can literally catch and read through anything and this sort of brings a lot of problems, especially when it comes to competent isolation. Whenever somebody whenever whenever a method is cat throwing an exception, you never know where that could be caught and you really have to hunt down hunted down. So I in my book exceptions are like warm holes right because they just take your execution point to somewhere else that even very famously called go to where they suddenly. Well, for example, let me take this analogy when you're sort of reading somebody else's code or your own code for that matter after a while. And there are always two IDs running and the one that runs on your laptop just fine. I doesn't have any problem because it has so much ramp to consume. And the other poor one which runs you know skull, which slowly reads line by line and sort of makes a picture slowly, which suddenly gets shattered by a throw statement because you'd never know where that gets caught. So for example, I will just talk to you simple examples and how we can solve them to avoid exceptions. For example, this particular code is trying to convey that okay, I have some problem, but I don't know how to convey when I don't have a problem. So what I do is I just throw exceptions whenever I have a problem. So, in the end, this sort of is bound to the caller the caller is supposed to handle this, and a notorious caller might even throw it back, and sometimes it just goes on caught to all the stuff and that's actress. So, the actual problem here is it's not able to convey the effect of absence for which it should actually use optional. So, in this code when there is no problem it should written optional dot empty, and you could see you can happily get away from exceptions and now the caller is no more sort of bound to catch it or handle it or even re throw it, it can simply get a result back and just work on that. This way, this particular component verify user access is isolated, whatever it does is inside this particular code piece and then you can literally refactor this without affecting the caller. And as you're adhering to the contract, of course. So my point is, you should really be able to replace all the exceptions with ADT, unless they're really exceptional, it is of course stand for algebraic data types. And some of them some very common simple ones, my focus is not going complicated or complex, like monads, etc. But I'm just going to focus on simple ADT that you can use that come out of the box, or maybe from some third party library, like optional and share presents one into one with another like a pair, and then either, which is left or right to be frank, there is a monad, but it's not not really scary, it's just just an interface having two different implementations. Of course, I can't go into details of this talk, but this fundamental link has all the documentation of what is an either and now how you can use it. We're also going to see some few examples now how we can use either. And, and with the advent of pattern matching in Java 16 plus, these are going to blend more naturally into the, into the language, so it's more easy to have a switch case statement, etc. On these ADTs now that there's pattern matching available. One example we can see is exception being misused to written multiple data type so sometimes the function might be in a scenario where I have to return something if everything is good but then have to return something else when some things are not correct. But of course we all know there is only one written data type so in that case is we sort of resort to throwing exceptions in cases where I don't know what to do. But this case is also the perfect fit for this is using an either. So instead of throwing an exception, you should be able to use an either and put your, or put your exception on the left state. Again, I can't go into details but once you understand either you actually get to understand what it is. So, and when everything is wrong you can put it on the right state so this particular component again is not dependent on exceptions and it's totally returning back a result rather than throwing an exception, which is an unfortunate side effect. So, that's it. My so I say throw away exceptions, never ever use it I mean just try as much as you can not use exception they can be exceptions scenarios, especially working with legacy code but try to not use them. Next we're going to talk about mutable state. I mean shared mutable state. That's shared mutable state on a shared code base. It's that's pretty scary. I'm going to tell you why. So let's start with the mutable objects as input patterns. So my point is they couple the components. So let's see with an example. Let's talk about a function simple function which is this taking list of numbers, and it's just summing them up returning result nothing fancy. And somebody wants to extend this particular function so he wrote something called some absolute. And what he does is this take that numbers and change all the numbers to positives and then he's just going to use the same some function to get all the some of all the numbers. Fine. It's all good. And they have used to some absolute in a particular production client code base, and it's working, they all went for a cheer party. Again, as a simple example, I want just to you to magnify what happens in production. Now, now, let's see what happens in production some other new joining joined and then he wants to extend. Now the client wants to also use some function, and he called some function here but then he got a result of 13. Ideally, he should have got minus eight plus five and it's minus three, but then he got this unholy digital 13. Why because he just got bitten by latent bug in real production scenarios you sort of end up by doing a very painful debugging session to understand that somebody has mutated your data set. And in my book, it's it's not a problem of some absolute who sort of got a mutable data set and then he took that as a license to do whatever on it mutated that because he got a mutable data structure. He can do whatever he wants in my book the problem is with the client that he is just passing around this mutable data structure to different points. Now, because of this mutable data set, both this client and some absolute a tightly coupled so that once I call some absolute I'm no more can reuse that num data set. So this is a problem when you sort of pass these mutable objects as patterns. So, mutable objects as in parents is unholy for isolation. What about the ones which are certain types. You might think it's not so problematic but there is even a bigger problem. Let me explain. So take one more example. So this is again a mock example. I love boiled eggs so I keep using X in all the examples. So, imagine there is a laying egg laying date function, and it has to do a DB operation to get the laying date of the egg based on its ID, and it's heavy operation is assumed. So, assume there are two dependent components in somewhere to two different modules or something which are not connected at all. So this component is doing is a spoiler is laid egg in the first half what it does is it checks whether the laying date is before 15th of that particular month, and then it is true or false. And the second dependent component calculates the age of the egg based on the laying date like it dips from the current date and then it does that. Okay, and then. Okay, one day what happened is this is laid in the first half wanted to add some logging. Actually, when it has to log, he also need to log the month and the year. So, along with the date. So what he wanted to do is let me reuse the same date function. And then a date field that is being there, and then let me mutate that to 15 and then log it. Now you can predict what can happen but let me also take you through on another day. What happened is this this heavy operation, what the thought maybe we should optimize it. So they have cashed it into a hash map like this, and they're now not computing it if the agate is already been being used before. So there's pick it from the hash map and give it back. All right, with this. Imagine what will happen this dependent component to is affected because this guy has mutated the state without knowing that this is being cashed in a hash map. And now this dependent component to want to take that he always gets the date 15. So this is the problem here you if you even if you use this. You got even a bigger problem like mutation. This this happens very clearly on a code basis because you sort of fix something or change something at one place and somewhere else breaks and you sort of end up in a debugging section thinking why is the state of the in that particular way. So this always happens because these components are invisibly entangled I would call them like quantum entanglement where they both are in different modules but just because they're dependent on one common component which is written in a mutable set. Everything just got jumbled. So that's also the problem with pointers in Java and might not be specific to Java but in the JVM world to be honest. So it's like pass by references as possible. This is a very common and very popular question looking at the upwards and the views. So I myself got beaten by it a lot of times. So whenever you sort of pass a mutable reference. It's like you can anybody can do anything on it. So but why is mutability predominant in Java code and because power of defaults mutability is the default mode in Java. Sorry to disturb like we have last 10 minutes of your session. Sure. Thanks. So mutability is the default mode in Java and make immutability your default. That's what I would say. And that's not easy but just like any other things in life we need to adhere to discipline to be the default. So some quick wins make a habit of using final before you watch. So your references are not being good. Follow a mutable strategy from Oracle documentation. And if you're in pre Java you can use different third party libraries like Lombok and Java 16 plus of course has records as well. And Java is doing its part probably to sort of go slowly towards this immutability. So but then still I would encounter some anti mutables who say hey mutability is only for multi threading. I would tell them my brain is already concurrently running with all this faction. So there's no point saying that it's a single they're a multi-threaded. If it's about reading code I have to adhere to immutability. And immutable objects doesn't fit my imperative style. Of course as you can see mutability and imperative to your friends. Like if you're using mutable data structures, you ought to invite a mutation like this. But if you replace your mutable data structures with immutable data structures, you have to use transformation like this and you don't have a choice but to transform but because you can't mutate it. So I would say mutability and transformation are like couple they go hand in hand there is no choice. And immutable of course forces transformation. Now I don't have to tell you who's the wife and who's the husband. Doesn't immutability affect both? Even I would add you a link in Oracle documentation which says this is overestimated object creation. It's not really affecting both a lot. And there is a lot of improvement in garbage collection which sort of removes that particular problem. And Java is embracing immutability very slowly as we have discussed it has been introducing new and new stuff in each and every release. So you can go check out about all these. And we're also going to see hello world but I'm not going to go into details because of limited time. This is a sample application. Like I said I'm going to share your blog post where this is written in detail. I just kind of grace for this particular topic. So imagine this is how the code looks like where there is mutable data set that's being passed along the all the functions and we can sort of refactor that into changing the signature of the particular function like instead of using this mutable data structures, you can instead written this either and using immutable data structures and I'll be sharing you the code base where you can actually check in detail how this transformation or signature shift is being done is how all the components are being refactored into now each component is isolated and it's not it's not affected by the caller. And this is more like a maths derivation where input of one function happens to be the output of another and vice versa. So you can fit them simply like Lego pieces and this is how they sort of how the function composition looks like. And I'm gonna just grace from the slide pretty fast but you can go ahead and check it out. And how are we doing on our goals. I want to talk about cognitive complexity. Now this code was how it was before and it had a lot of problems like mutability and try catching etc. And this is of course is cognitive complexity without even checking any metrics. But this code this this is our final code where we refactor and is it really cognitive complex if you see a code like this, maybe I still encounter people who think this is cognitively complex. But let's check is really complexity the one that talking about is complex. So complexity can be of different types like accidental complexity essential complexity cognitive psychometric complexity and layers like unfamiliarity versus 100 degree district versus non extensible. So complexity here is essential complexity and it would be unfamiliarity of the person who has seen it or has not worked on Java 8 or some lambdas and functional aspects that can even be strict strictness like that's pretty intentional on that we have done. This is because we sort of want to have prepared some sort of lanes on which a particular particular developer has to adhere to without breaking the rules. So it's strict because it doesn't let you mutate you have to transform and the operators are in charge in here so it's also good that when somebody wants to extend this particular code he can't take shortcuts and do stuff it's it's like written ones and it's a future as well. That's it to objectively measure cognitive complexity you can check out my previous talks where I have heard in detail, and the testability part, even I just have one tip, but I can't go through it because of limited time so I'm just going to grace. So I shown you how brittle test is written because of it and I'll be telling you how unit test is also equal to test is not testing internals. So you've got to separate static from signal. I'm just going to grace to all these slides very fast and and I always say the stability should be first and test coverage always follows. So, and test and refactor should happen hand in hand. It's not an afterthought. So in the end entropy is inevitable no matter how many coding principles you follow the code as more people join in your team you people the entropy of the code base is going to increase for sure. But our goal is not to make it exponential, but then to keep it logarithmic over the time so that you sort of the code base doesn't fall out of place and all these things that we have discussed before will. Those are very simple tricks interrupts and you can follow them along to keep your entropy in check. Never ever do this just go ahead and refactor your code base in the end, because if you do this, this might can happen especially when you don't have this intention left last quadrant empty to for you to imagine what all can happen if you do it always refactor incrementally it's all it's okay to just good enough as long as you have this backing up, you can always find time to refactor it more. And I want to end up this talk with this great quote from clean code even backcode can function but if code isn't clean and can bring a development organization to its knees and never let them happen. You can find the slides here the code here in the blog post here as I promised please go ahead and check and you should be able to expand this 1520 minutes to some to watch stuff. You can be able to connect it out and always reach out to me if you have doubts and thanks a lot. Thank you, Gopal. Thank you everyone. Thanks. Bye bye.